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 // Note: Data validate occurs in func.createNS
172 if (namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
173 return func.createNS(trans, namespace, false);
176 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
179 public String get() {
180 return "Create Namespace [" + namespace.name + ']';
184 private Result<NsDAO.Data> rnd;
186 public Result<?> mayChange() {
188 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
195 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
197 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
199 return Result.err(rfc);
202 return func.createNS(trans, namespace, false);
204 return Result.err(fd);
210 path = "/authz/ns/:ns/admin/:id",
211 params = { "ns|string|true",
215 errorCodes = { 403,404,406,409 },
216 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
217 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
220 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
221 return func.addUserRole(trans, id, ns,Question.ADMIN);
226 path = "/authz/ns/:ns/admin/:id",
227 params = { "ns|string|true",
231 errorCodes = { 403,404 },
232 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
233 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
236 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
237 return func.delAdmin(trans,ns,id);
242 path = "/authz/ns/:ns/responsible/:id",
243 params = { "ns|string|true",
247 errorCodes = { 403,404,406,409 },
248 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
249 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
252 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
253 return func.addUserRole(trans,id,ns,Question.OWNER);
258 path = "/authz/ns/:ns/responsible/:id",
259 params = { "ns|string|true",
263 errorCodes = { 403,404 },
264 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
265 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
266 "Note: A namespace must have at least 1 responsible party"
270 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
271 return func.delOwner(trans,ns,id);
275 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
279 path = "/authz/ns/:ns/attrib/:key/:value",
280 params = { "ns|string|true",
282 "value|string|true"},
284 errorCodes = { 403,404,406,409 },
286 "Create an attribute in the Namespace",
287 "You must be given direct permission for key by AAF"
291 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
292 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
295 final Validator v = new ServiceValidator();
296 if (v.ns(ns).err() ||
298 v.value(value).err()) {
299 return Result.err(Status.ERR_BadData,v.errs());
302 // Check if exists already
303 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
304 if (rlnsd.notOKorIsEmpty()) {
305 return Result.err(rlnsd);
307 NsDAO.Data nsd = rlnsd.value.get(0);
309 // Check for Existence
310 if (nsd.attrib.get(key)!=null) {
311 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
314 // Check if User may put
315 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
316 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
317 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
321 nsd.attrib.put(key, value);
322 ques.nsDAO().dao().attribAdd(trans,ns,key,value);
323 ques.nsDAO().invalidate(trans, nsd);
332 path = "/authz/ns/attrib/:key",
333 params = { "key|string|true" },
335 errorCodes = { 403,404 },
337 "Read Attributes for Namespace"
341 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
343 final Validator v = new ServiceValidator();
344 if (v.nullOrBlank("Key",key).err()) {
345 return Result.err(Status.ERR_BadData,v.errs());
349 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
350 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
351 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
354 Result<Set<String>> rsd = ques.nsDAO().dao().readNsByAttrib(trans, key);
356 return Result.err(rsd);
358 return mapper().keys(rsd.value);
364 path = "/authz/ns/:ns/attrib/:key/:value",
365 params = { "ns|string|true",
368 errorCodes = { 403,404 },
370 "Update Value on an existing attribute in the Namespace",
371 "You must be given direct permission for key by AAF"
375 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
376 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
379 final Validator v = new ServiceValidator();
380 if (v.ns(ns).err() ||
382 v.value(value).err()) {
383 return Result.err(Status.ERR_BadData,v.errs());
386 // Check if exists already (NS must exist)
387 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
388 if (rlnsd.notOKorIsEmpty()) {
389 return Result.err(rlnsd);
391 NsDAO.Data nsd = rlnsd.value.get(0);
393 // Check for Existence
394 if (nsd.attrib.get(key)==null) {
395 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
398 // Check if User may put
399 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
400 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
401 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
405 nsd.attrib.put(key, value);
406 ques.nsDAO().invalidate(trans, nsd);
407 return ques.nsDAO().update(trans,nsd);
416 path = "/authz/ns/:ns/attrib/:key",
417 params = { "ns|string|true",
420 errorCodes = { 403,404 },
422 "Delete an attribute in the Namespace",
423 "You must be given direct permission for key by AAF"
427 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
428 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
431 final Validator v = new ServiceValidator();
432 if (v.nullOrBlank("NS",ns).err() ||
433 v.nullOrBlank("Key",key).err()) {
434 return Result.err(Status.ERR_BadData,v.errs());
437 // Check if exists already
438 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
439 if (rlnsd.notOKorIsEmpty()) {
440 return Result.err(rlnsd);
442 NsDAO.Data nsd = rlnsd.value.get(0);
444 // Check for Existence
445 if (nsd.attrib.get(key)==null) {
446 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
449 // Check if User may del
450 if (!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
451 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
455 nsd.attrib.remove(key);
456 ques.nsDAO().dao().attribRemove(trans,ns,key);
457 ques.nsDAO().invalidate(trans, nsd);
466 path = "/authz/nss/:id",
467 params = { "id|string|true" },
469 errorCodes = { 404,406 },
471 "Lists the Owner(s), Admin(s), Description, and Attributes of Namespace :id",
475 public Result<NSS> getNSbyName(AuthzTrans trans, String ns, boolean includeExpired) {
476 final Validator v = new ServiceValidator();
477 if (v.nullOrBlank("NS", ns).err()) {
478 return Result.err(Status.ERR_BadData,v.errs());
481 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, ns);
483 if (rlnd.isEmpty()) {
484 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
486 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
488 return Result.err(rnd);
492 Namespace namespace = new Namespace(rnd.value);
493 Result<List<String>> rd = func.getOwners(trans, namespace.name, includeExpired);
495 namespace.owner = rd.value;
497 rd = func.getAdmins(trans, namespace.name, includeExpired);
499 namespace.admin = rd.value;
502 NSS nss = mapper.newInstance(API.NSS);
503 return mapper.nss(trans, namespace, nss);
505 return Result.err(rlnd);
511 path = "/authz/nss/admin/:id",
512 params = { "id|string|true" },
514 errorCodes = { 403,404 },
515 text = { "Lists all Namespaces where Identity :id is an Admin",
516 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
520 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
521 final Validator v = new ServiceValidator();
522 if (v.nullOrBlank("User", user).err()) {
523 return Result.err(Status.ERR_BadData, v.errs());
526 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
528 return Result.err(rn);
531 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
533 NSS nss = mapper.newInstance(API.NSS);
534 // Note: "loadNamespace" already validates view of Namespace
535 return mapper.nss(trans, rn.value, nss);
540 path = "/authz/nss/either/:id",
541 params = { "id|string|true" },
543 errorCodes = { 403,404 },
544 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
545 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
549 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
550 final Validator v = new ServiceValidator();
551 if (v.nullOrBlank("User", user).err()) {
552 return Result.err(Status.ERR_BadData, v.errs());
555 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
557 return Result.err(rn);
560 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
562 NSS nss = mapper.newInstance(API.NSS);
563 // Note: "loadNamespace" already validates view of Namespace
564 return mapper.nss(trans, rn.value, nss);
567 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
568 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO().readByUser(trans, user);
569 if (urd.notOKorIsEmpty()) {
570 return Result.err(urd);
572 Map<String, Namespace> lm = new HashMap<>();
573 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<>();
574 for (UserRoleDAO.Data urdd : urd.value) {
576 if (endsWith==null || urdd.role.endsWith(endsWith)) {
577 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
578 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
580 Namespace namespace = lm.get(nsd.value.name);
581 if (namespace==null) {
582 namespace = new Namespace(nsd.value);
583 lm.put(namespace.name,namespace);
585 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
587 namespace.admin=rls.value;
590 rls = func.getOwners(trans, namespace.name, false);
592 namespace.owner=rls.value;
596 } else { // Shortened version. Only Namespace Info available from Role.
597 if (Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
598 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
599 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
601 Namespace namespace = lm.get(nsd.value.name);
602 if (namespace==null) {
604 namespace = other.remove(nsd.value.name);
606 if (namespace==null) {
607 namespace = new Namespace(nsd.value);
608 namespace.admin=new ArrayList<>();
609 namespace.owner=new ArrayList<>();
611 if (endsWith==null || urdd.role.endsWith(endsWith)) {
612 lm.put(namespace.name,namespace);
614 other.put(namespace.name,namespace);
617 if (Question.OWNER.equals(urdd.rname)) {
618 namespace.owner.add(urdd.user);
620 namespace.admin.add(urdd.user);
626 return Result.ok(lm.values());
631 path = "/authz/nss/responsible/:id",
632 params = { "id|string|true" },
634 errorCodes = { 403,404 },
635 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
636 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
640 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
641 final Validator v = new ServiceValidator();
642 if (v.nullOrBlank("User", user).err()) {
643 return Result.err(Status.ERR_BadData, v.errs());
645 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
647 return Result.err(rn);
650 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
652 NSS nss = mapper.newInstance(API.NSS);
653 // Note: "loadNamespace" prevalidates
654 return mapper.nss(trans, rn.value, nss);
659 path = "/authz/nss/children/:id",
660 params = { "id|string|true" },
662 errorCodes = { 403,404 },
663 text = { "Lists all Child Namespaces of Namespace :id",
664 "Note: This is not a cached read"
668 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
669 final Validator v = new ServiceValidator();
670 if (v.nullOrBlank("NS", parent).err()) {
671 return Result.err(Status.ERR_BadData,v.errs());
674 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
676 return Result.err(rnd);
678 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
680 return Result.err(rnd);
683 Set<Namespace> lm = new HashSet<>();
684 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().dao().getChildren(trans, parent);
686 if (rlnd.isEmpty()) {
687 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
689 for (NsDAO.Data ndd : rlnd.value) {
690 Namespace namespace = new Namespace(ndd);
691 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
693 namespace.admin=rls.value;
696 rls = func.getOwners(trans, namespace.name, false);
698 namespace.owner=rls.value;
703 NSS nss = mapper.newInstance(API.NSS);
704 return mapper.nss(trans,lm, nss);
706 return Result.err(rlnd);
716 errorCodes = { 403,404,406 },
717 text = { "Replace the Current Description of a Namespace with a new one"
721 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
722 final Result<Namespace> nsd = mapper.ns(trans, from);
723 final ServiceValidator v = new ServiceValidator();
724 if (v.ns(nsd).err()) {
725 return Result.err(Status.ERR_BadData,v.errs());
727 if (v.nullOrBlank("description", nsd.value.description).err()) {
728 return Result.err(Status.ERR_BadData,v.errs());
731 Namespace namespace = nsd.value;
732 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, namespace.name);
734 if (rlnd.notOKorIsEmpty()) {
735 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
738 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
739 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
742 Result<Void> rdr = ques.nsDAO().dao().addDescription(trans, namespace.name, namespace.description);
746 return Result.err(rdr);
752 * @throws DAOException
753 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
757 path = "/authz/ns/:ns",
758 params = { "ns|string|true" },
760 errorCodes = { 403,404,424 },
761 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
762 "are still credentials associated with them, but they can be deleted by setting ",
763 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
764 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
765 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
766 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
767 + "at or below Application Scope"
771 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
772 return func.deleteNS(trans, ns);
776 /***********************************
778 ***********************************/
782 * @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)
786 path = "/authz/perm",
789 errorCodes = {403,404,406,409},
790 text = { "Permission consists of:",
791 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
792 + "is being protected</li>",
793 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
794 + " instance of the type</li>",
795 "<li>action - what kind of action is allowed</li></ul>",
796 "Note: instance and action can be an *"
800 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
801 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
802 // Does Perm Type exist as a Namespace?
803 if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
804 return Result.err(Status.ERR_ConflictAlreadyExists,
805 "Permission Type exists as a Namespace");
808 final ServiceValidator v = new ServiceValidator();
809 if (v.perm(newPd).err()) {
810 return Result.err(Status.ERR_BadData,v.errs());
813 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
816 public String get() {
817 return "Create Permission [" +
818 newPd.value.fullType() + '|' +
819 newPd.value.instance + '|' +
820 newPd.value.action + ']';
824 private Result<NsDAO.Data> nsd;
826 public Result<?> mayChange() {
828 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
833 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
834 if (nsr.notOKorIsEmpty()) {
835 return Result.err(nsr);
839 Result<String> rfc = func.createFuture(trans,fd.value,
840 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
845 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
848 newPd.value.instance,
851 return Result.err(rfc);
854 return func.createPerm(trans, newPd.value, true);
856 return Result.err(fd);
862 path = "/authz/perms/:type",
863 params = {"type|string|true"},
865 errorCodes = { 404,406 },
866 text = { "List All Permissions that match the :type element of the key" }
869 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
870 final Validator v = new ServiceValidator();
871 if (v.nullOrBlank("PermType", permType).err()) {
872 return Result.err(Status.ERR_BadData,v.errs());
875 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
877 return Result.err(rlpd);
880 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
881 // Result<NsDAO.Data> r;
882 // if ((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
884 PERMS perms = mapper.newInstance(API.PERMS);
885 if (!rlpd.isEmpty()) {
886 // Note: Mapper will restrict what can be viewed
887 return mapper.perms(trans, rlpd.value, perms, true);
889 return Result.ok(perms);
894 path = "/authz/perms/:type/:instance/:action",
895 params = {"type|string|true",
896 "instance|string|true",
897 "action|string|true"},
899 errorCodes = { 404,406 },
900 text = { "List Permissions that match key; :type, :instance and :action" }
903 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
904 final Validator v = new ServiceValidator();
905 if (v.nullOrBlank("PermType", type).err()
906 || v.nullOrBlank("PermInstance", instance).err()
907 || v.nullOrBlank("PermAction", action).err()) {
908 return Result.err(Status.ERR_BadData,v.errs());
911 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
913 return Result.err(rlpd);
916 PERMS perms = mapper.newInstance(API.PERMS);
917 if (!rlpd.isEmpty()) {
918 // Note: Mapper will restrict what can be viewed
919 return mapper.perms(trans, rlpd.value, perms, true);
921 return Result.ok(perms);
926 path = "/authz/perms/user/:user",
927 params = {"user|string|true"},
929 errorCodes = { 404,406 },
930 text = { "List All Permissions that match user :user",
931 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
934 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
935 final Validator v = new ServiceValidator();
936 if (v.nullOrBlank("User", user).err()) {
937 return Result.err(Status.ERR_BadData,v.errs());
940 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,
941 trans.requested(force));
943 return Result.err(rlpd);
946 PERMS perms = mapper.newInstance(API.PERMS);
948 if (rlpd.isEmpty()) {
949 return Result.ok(perms);
951 // Note: Mapper will restrict what can be viewed
952 // if user is the same as that which is looked up, no filtering is required
953 return mapper.perms(trans, rlpd.value,
955 !user.equals(trans.user()));
960 path = "/authz/perms/user/:user/scope/:scope",
961 params = {"user|string|true","scope|string|true"},
963 errorCodes = { 404,406 },
964 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
965 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
966 "<p>'scope' must be expressed as NSs separated by ':'</p>"
970 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
971 final Validator v = new ServiceValidator();
972 if (v.nullOrBlank("User", user).err()) {
973 return Result.err(Status.ERR_BadData,v.errs());
976 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
978 return Result.err(rlpd);
981 PERMS perms = mapper.newInstance(API.PERMS);
983 if (rlpd.isEmpty()) {
984 return Result.ok(perms);
986 // Note: Mapper will restrict what can be viewed
987 // if user is the same as that which is looked up, no filtering is required
988 return mapper.perms(trans, rlpd.value,
991 !user.equals(trans.user()));
996 path = "/authz/perms/user/:user",
997 params = {"user|string|true"},
999 errorCodes = { 404,406 },
1000 text = { "List All Permissions that match user :user",
1001 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1003 "Present Queries as one or more Permissions (see ContentType Links below for format).",
1005 "If the Caller is Granted this specific Permission, and the Permission is valid",
1006 " for the User, it will be included in response Permissions, along with",
1007 " all the normal permissions on the 'GET' version of this call. If it is not",
1008 " valid, or Caller does not have permission to see, it will be removed from the list",
1010 " *Note: This design allows you to make one call for all expected permissions",
1011 " The permission to be included MUST be:",
1012 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1014 " com.att.myns.access|:ns|write",
1015 " com.att.myns.access|:role:myrole|create",
1016 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1021 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1022 PERMS perms = _perms;
1023 final Validator v = new ServiceValidator();
1024 if (v.nullOrBlank("User", user).err()) {
1025 return Result.err(Status.ERR_BadData,v.errs());
1029 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.requested(force));
1031 return Result.err(rlpd);
1035 1) See if allowed to query
1036 2) See if User is allowed
1038 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1039 if (in.isOKhasData()) {
1040 List<PermDAO.Data> out = rlpd.value;
1042 for (PermDAO.Data pdd : in.value) {
1044 if ("access".equals(pdd.type)) {
1045 Access access = Access.valueOf(pdd.action);
1046 String[] mdkey = Split.splitTrim(':',pdd.instance);
1047 if (mdkey.length>1) {
1048 String type = mdkey[1];
1049 if ("role".equals(type)) {
1050 if (mdkey.length>2) {
1051 RoleDAO.Data rdd = new RoleDAO.Data();
1054 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1056 } else if ("perm".equals(type)) {
1057 if (mdkey.length>4) { // also need instance/action
1058 PermDAO.Data p = new PermDAO.Data();
1061 p.instance=mdkey[3];
1063 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1065 } else if ("ns".equals(type)) {
1066 NsDAO.Data ndd = new NsDAO.Data();
1068 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1078 perms = mapper.newInstance(API.PERMS);
1079 if (rlpd.isEmpty()) {
1080 return Result.ok(perms);
1082 // Note: Mapper will restrict what can be viewed
1083 // if user is the same as that which is looked up, no filtering is required
1084 return mapper.perms(trans, rlpd.value,
1086 !user.equals(trans.user()));
1091 path = "/authz/perms/role/:role",
1092 params = {"role|string|true"},
1094 errorCodes = { 404,406 },
1095 text = { "List All Permissions that are granted to :role" }
1098 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1099 final Validator v = new ServiceValidator();
1100 if (v.nullOrBlank("Role", role).err()) {
1101 return Result.err(Status.ERR_BadData,v.errs());
1104 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1106 return Result.err(rrdd);
1109 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1111 return Result.err(r);
1114 PERMS perms = mapper.newInstance(API.PERMS);
1116 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1117 if (rlpd.isOKhasData()) {
1118 // Note: Mapper will restrict what can be viewed
1119 return mapper.perms(trans, rlpd.value, perms, true);
1121 return Result.ok(perms);
1126 path = "/authz/perms/ns/:ns",
1127 params = {"ns|string|true"},
1129 errorCodes = { 404,406 },
1130 text = { "List All Permissions that are in Namespace :ns" }
1133 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1134 final Validator v = new ServiceValidator();
1135 if (v.nullOrBlank("NS", ns).err()) {
1136 return Result.err(Status.ERR_BadData,v.errs());
1139 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1141 return Result.err(rnd);
1144 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1146 return Result.err(rnd);
1149 Result<List<PermDAO.Data>> rlpd = ques.permDAO().readNS(trans, ns);
1151 return Result.err(rlpd);
1154 PERMS perms = mapper.newInstance(API.PERMS);
1155 if (!rlpd.isEmpty()) {
1156 // Note: Mapper will restrict what can be viewed
1157 return mapper.perms(trans, rlpd.value,perms, true);
1159 return Result.ok(perms);
1164 path = "/authz/perm/:type/:instance/:action",
1165 params = {"type|string|true",
1166 "instance|string|true",
1167 "action|string|true"},
1169 errorCodes = { 404,406, 409 },
1170 text = { "Rename the Permission referenced by :type :instance :action, and "
1171 + "rename (copy/delete) to the Permission described in PermRequest" }
1174 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1175 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1176 final ServiceValidator v = new ServiceValidator();
1177 if (v.perm(newPd).err()) {
1178 return Result.err(Status.ERR_BadData,v.errs());
1181 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1182 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1183 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1186 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1187 Result<List<PermDAO.Data>> origRlpd = ques.permDAO().read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1189 if (origRlpd.notOKorIsEmpty()) {
1190 return Result.err(Status.ERR_PermissionNotFound,
1191 "Permission [%s|%s|%s] does not exist",
1192 origType,origInstance,origAction);
1195 PermDAO.Data origPd = origRlpd.value.get(0);
1197 if (!origPd.ns.equals(newPd.value.ns)) {
1198 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1199 "<new type> must start with [" + origPd.ns + "]");
1202 if ( origPd.type.equals(newPd.value.type) &&
1203 origPd.action.equals(newPd.value.action) &&
1204 origPd.instance.equals(newPd.value.instance) ) {
1205 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1208 Set<String> origRoles = origPd.roles(false);
1209 if (!origRoles.isEmpty()) {
1210 Set<String> roles = newPd.value.roles(true);
1211 for (String role : origPd.roles) {
1216 newPd.value.description = origPd.description;
1218 Result<Void> rv = null;
1220 rv = func.createPerm(trans, newPd.value, false);
1222 rv = func.deletePerm(trans, origPd, true, false);
1229 path = "/authz/perm",
1232 errorCodes = { 404,406 },
1233 text = { "Add Description Data to Perm" }
1236 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1237 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1238 final ServiceValidator v = new ServiceValidator();
1239 if (v.perm(pd).err()) {
1240 return Result.err(Status.ERR_BadData,v.errs());
1242 if (v.nullOrBlank("description", pd.value.description).err()) {
1243 return Result.err(Status.ERR_BadData,v.errs());
1245 final PermDAO.Data perm = pd.value;
1246 if (ques.permDAO().read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1247 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1248 perm.ns,perm.type,perm.instance,perm.action);
1251 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1252 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1253 perm.ns,perm.type,perm.instance,perm.action);
1256 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pd.value.ns);
1257 if (nsr.notOKorIsEmpty()) {
1258 return Result.err(nsr);
1261 Result<Void> rdr = ques.permDAO().addDescription(trans, perm.ns, perm.type, perm.instance,
1262 perm.action, perm.description);
1266 return Result.err(rdr);
1273 path = "/authz/role/perm",
1276 errorCodes = {403,404,406,409},
1277 text = { "Set a permission's roles to roles given" }
1281 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1282 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1283 if (updt.notOKorIsEmpty()) {
1284 return Result.err(updt);
1287 final ServiceValidator v = new ServiceValidator();
1288 if (v.perm(updt).err()) {
1289 return Result.err(Status.ERR_BadData,v.errs());
1292 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1294 return Result.err(nsd);
1297 // Read full set to get CURRENT values
1298 Result<List<PermDAO.Data>> rcurr = ques.permDAO().read(trans,
1301 updt.value.instance,
1304 if (rcurr.notOKorIsEmpty()) {
1305 return Result.err(Status.ERR_PermissionNotFound,
1306 "Permission [%s.%s|%s|%s] does not exist",
1307 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1310 // Create a set of Update Roles, which are in Internal Format
1311 Set<String> updtRoles = new HashSet<>();
1312 Result<NsSplit> nss;
1313 for (String role : updt.value.roles(false)) {
1314 nss = ques.deriveNsSplit(trans, role);
1316 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1318 trans.error().log(nss.errorString());
1322 Result<Void> rv = null;
1324 for (PermDAO.Data curr : rcurr.value) {
1325 Set<String> currRoles = curr.roles(false);
1326 // must add roles to this perm, and add this perm to each role
1327 // in the update, but not in the current
1328 for (String role : updtRoles) {
1329 if (!currRoles.contains(role)) {
1330 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1331 if (key.isOKhasData()) {
1332 Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, key.value);
1333 if (rrd.isOKhasData()) {
1334 for (RoleDAO.Data r : rrd.value) {
1335 rv = func.addPermToRole(trans, r, curr, false);
1336 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1337 return Result.err(rv);
1341 return Result.err(rrd);
1346 // similarly, must delete roles from this perm, and delete this perm from each role
1347 // in the update, but not in the current
1348 for (String role : currRoles) {
1349 if (!updtRoles.contains(role)) {
1350 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1351 if (key.isOKhasData()) {
1352 Result<List<RoleDAO.Data>> rdd = ques.roleDAO().read(trans, key.value);
1353 if (rdd.isOKhasData()) {
1354 for (RoleDAO.Data r : rdd.value) {
1355 rv = func.delPermFromRole(trans, r, curr, true);
1356 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1357 return Result.err(rv);
1365 return rv==null?Result.ok():rv;
1370 path = "/authz/perm",
1373 errorCodes = { 404,406 },
1374 text = { "Delete the Permission referenced by PermKey.",
1375 "You cannot normally delete a permission which is still granted to roles,",
1376 "however the \"force\" property allows you to do just that. To do this: Add",
1377 "'force=true' as a query parameter.",
1378 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1381 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1382 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1384 return Result.err(pd);
1386 final ServiceValidator v = new ServiceValidator();
1387 if (v.nullOrBlank(pd.value).err()) {
1388 return Result.err(Status.ERR_BadData,v.errs());
1390 final PermDAO.Data perm = pd.value;
1391 if (ques.permDAO().read(trans, perm).notOKorIsEmpty()) {
1392 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1393 perm.ns,perm.type,perm.instance,perm.action );
1396 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1399 public String get() {
1400 return "Delete Permission [" + perm.fullPerm() + ']';
1404 private Result<NsDAO.Data> nsd;
1406 public Result<?> mayChange() {
1408 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1416 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, perm.ns);
1417 if (nsr.notOKorIsEmpty()) {
1418 return Result.err(nsr);
1421 Result<String> rfc = func.createFuture(trans, fd.value,
1422 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1424 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1426 return Result.err(rfc);
1428 case Status.ACC_Now:
1429 return func.deletePerm(trans,perm,trans.requested(force), false);
1431 return Result.err(fd);
1437 path = "/authz/perm/:name/:type/:action",
1438 params = {"type|string|true",
1439 "instance|string|true",
1440 "action|string|true"},
1442 errorCodes = { 404,406 },
1443 text = { "Delete the Permission referenced by :type :instance :action",
1444 "You cannot normally delete a permission which is still granted to roles,",
1445 "however the \"force\" property allows you to do just that. To do this: Add",
1446 "'force=true' as a query parameter",
1447 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1450 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1451 final Validator v = new ServiceValidator();
1452 if (v.nullOrBlank("Type",type)
1453 .nullOrBlank("Instance",instance)
1454 .nullOrBlank("Action",action)
1456 return Result.err(Status.ERR_BadData,v.errs());
1459 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1461 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1463 return Result.err(pd);
1467 /***********************************
1469 ***********************************/
1472 path = "/authz/role",
1475 errorCodes = {403,404,406,409},
1478 "Roles are part of Namespaces",
1480 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1481 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1482 "Restrictions on Role Names:",
1483 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1484 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1485 "<li>role names are Case Sensitive</li></ul>",
1486 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1487 "<ul><li>'What Job Function does this represent?'</li>",
1488 "<li>'Does this person perform this Job Function?'</li></ul>" }
1492 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1493 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1494 // Does Perm Type exist as a Namespace?
1495 if(rd.value.name.isEmpty() || ques.nsDAO().read(trans, rd.value.fullName()).isOKhasData()) {
1496 return Result.err(Status.ERR_ConflictAlreadyExists,
1497 "Role exists as a Namespace");
1499 final ServiceValidator v = new ServiceValidator();
1500 if (v.role(rd).err()) {
1501 return Result.err(Status.ERR_BadData,v.errs());
1503 final RoleDAO.Data role = rd.value;
1504 if (ques.roleDAO().read(trans, role.ns, role.name).isOKhasData()) {
1505 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1508 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1511 public String get() {
1512 return "Create Role [" +
1513 rd.value.fullName() +
1518 private Result<NsDAO.Data> nsd;
1520 public Result<?> mayChange() {
1522 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1528 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1529 if (nsr.notOKorIsEmpty()) {
1530 return Result.err(nsr);
1535 Result<String> rfc = func.createFuture(trans, fd.value,
1536 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1538 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1542 return Result.err(rfc);
1544 case Status.ACC_Now:
1545 Result<RoleDAO.Data> rdr = ques.roleDAO().create(trans, role);
1549 return Result.err(rdr);
1552 return Result.err(fd);
1557 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1561 path = "/authz/roles/:role",
1562 params = {"role|string|true"},
1564 errorCodes = {404,406},
1565 text = { "List Roles that match :role",
1566 "Note: You must have permission to see any given role"
1570 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1571 final Validator v = new ServiceValidator();
1572 if (v.nullOrBlank("Role", role).err()) {
1573 return Result.err(Status.ERR_BadData,v.errs());
1576 // Determine if User can ask this question
1577 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1578 if (rrdd.isOKhasData()) {
1579 Result<NsDAO.Data> r;
1580 if ((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1581 return Result.err(r);
1584 return Result.err(rrdd);
1588 int query = role.indexOf('?');
1589 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1591 // Note: Mapper will restrict what can be viewed
1592 ROLES roles = mapper.newInstance(API.ROLES);
1593 return mapper.roles(trans, rlrd.value, roles, true);
1595 return Result.err(rlrd);
1600 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1604 path = "/authz/roles/user/:name",
1605 params = {"name|string|true"},
1607 errorCodes = {404,406},
1608 text = { "List all Roles that match user :name",
1609 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1610 "Note: You must have permission to see any given role"
1615 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1616 final Validator v = new ServiceValidator();
1617 if (v.nullOrBlank("User", user).err()) {
1618 return Result.err(Status.ERR_BadData,v.errs());
1621 ROLES roles = mapper.newInstance(API.ROLES);
1622 // Get list of roles per user, then add to Roles as we go
1623 Result<List<RoleDAO.Data>> rlrd;
1624 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
1625 if (rlurd.isOKhasData()) {
1626 for (UserRoleDAO.Data urd : rlurd.value ) {
1627 rlrd = ques.roleDAO().read(trans, urd.ns,urd.rname);
1628 // Note: Mapper will restrict what can be viewed
1629 // if user is the same as that which is looked up, no filtering is required
1630 if (rlrd.isOKhasData()) {
1631 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1635 return Result.ok(roles);
1640 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1644 path = "/authz/roles/ns/:ns",
1645 params = {"ns|string|true"},
1647 errorCodes = {404,406},
1648 text = { "List all Roles for the Namespace :ns",
1649 "Note: You must have permission to see any given role"
1654 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1655 final Validator v = new ServiceValidator();
1656 if (v.nullOrBlank("NS", ns).err()) {
1657 return Result.err(Status.ERR_BadData,v.errs());
1660 // check if user is allowed to view NS
1661 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1663 return Result.err(rnsd);
1665 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1667 return Result.err(rnsd);
1670 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1672 ROLES roles = mapper.newInstance(API.ROLES);
1673 // Get list of roles per user, then add to Roles as we go
1674 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readNS(trans, ns);
1676 if (!rlrd.isEmpty()) {
1677 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1678 mapper.roles(trans,rlrd.value,roles,false);
1680 return Result.ok(roles);
1682 return Result.err(rlrd);
1691 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1695 path = "/authz/roles/name/:name",
1696 params = {"name|string|true"},
1698 errorCodes = {404,406},
1699 text = { "List all Roles for only the Name of Role (without Namespace)",
1700 "Note: You must have permission to see any given role"
1704 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1705 final Validator v = new ServiceValidator();
1706 if (v.nullOrBlank("Name", name).err()) {
1707 return Result.err(Status.ERR_BadData,v.errs());
1710 // User Mapper to make sure user is allowed to view NS
1712 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1714 ROLES roles = mapper.newInstance(API.ROLES);
1715 // Get list of roles per user, then add to Roles as we go
1716 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readName(trans, name);
1718 if (!rlrd.isEmpty()) {
1719 // Note: Mapper will restrict what can be viewed
1720 mapper.roles(trans,rlrd.value,roles,true);
1722 return Result.ok(roles);
1724 return Result.err(rlrd);
1733 path = "/authz/roles/perm/:type/:instance/:action",
1734 params = {"type|string|true",
1735 "instance|string|true",
1736 "action|string|true"},
1738 errorCodes = {404,406},
1739 text = { "Find all Roles containing the given Permission." +
1740 "Permission consists of:",
1741 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1742 + "is being protected</li>",
1743 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1744 + " instance of the type</li>",
1745 "<li>action - what kind of action is allowed</li></ul>",
1746 "Notes: instance and action can be an *",
1747 " You must have permission to see any given role"
1752 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1753 final Validator v = new ServiceValidator();
1754 if (v.permType(type)
1755 .permInstance(instance)
1758 return Result.err(Status.ERR_BadData,v.errs());
1761 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1763 ROLES roles = mapper.newInstance(API.ROLES);
1764 // Get list of roles per user, then add to Roles as we go
1765 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1766 if (nsSplit.isOK()) {
1767 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1769 if ((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1770 return Result.err(res);
1773 Result<List<PermDAO.Data>> pdlr = ques.permDAO().read(trans, pdd);
1774 if (pdlr.isOK())for (PermDAO.Data pd : pdlr.value) {
1775 Result<List<RoleDAO.Data>> rlrd;
1776 for (String r : pd.roles) {
1777 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1779 rlrd = ques.roleDAO().read(trans, rs.value[0],rs.value[1]);
1780 // Note: Mapper will restrict what can be viewed
1781 if (rlrd.isOKhasData()) {
1782 mapper.roles(trans,rlrd.value,roles,true);
1788 return Result.ok(roles);
1796 path = "/authz/role",
1799 errorCodes = {404,406},
1800 text = { "Add Description Data to a Role" }
1804 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1805 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1806 final ServiceValidator v = new ServiceValidator();
1807 if (v.role(rd).err()) {
1808 return Result.err(Status.ERR_BadData,v.errs());
1810 if (v.nullOrBlank("description", rd.value.description).err()) {
1811 return Result.err(Status.ERR_BadData,v.errs());
1814 final RoleDAO.Data role = rd.value;
1815 if (ques.roleDAO().read(trans, role.ns, role.name).notOKorIsEmpty()) {
1816 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1819 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1820 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1823 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1824 if (nsr.notOKorIsEmpty()) {
1825 return Result.err(nsr);
1828 Result<Void> rdr = ques.roleDAO().addDescription(trans, role.ns, role.name, role.description);
1832 return Result.err(rdr);
1839 path = "/authz/role/perm",
1842 errorCodes = {403,404,406,409},
1843 text = { "Grant a Permission to a Role",
1844 "Permission consists of:",
1845 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1846 + "is being protected</li>",
1847 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1848 + " instance of the type</li>",
1849 "<li>action - what kind of action is allowed</li></ul>",
1850 "Note: instance and action can be an *",
1851 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1852 " ID is allowed to create. It will then grant",
1853 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1858 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1859 // Translate Request into Perm and Role Objects
1860 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1861 if (rpd.notOKorIsEmpty()) {
1862 return Result.err(rpd);
1864 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1865 if (rrd.notOKorIsEmpty()) {
1866 return Result.err(rrd);
1869 // Validate Role and Perm values
1870 final ServiceValidator v = new ServiceValidator();
1871 if (v.perm(rpd.value)
1874 return Result.err(Status.ERR_BadData,v.errs());
1877 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().read(trans, rrd.value.ns, rrd.value.name);
1878 if (rlrd.notOKorIsEmpty()) {
1879 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1882 // Check Status of Data in DB (does it exist)
1883 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, rpd.value.ns,
1884 rpd.value.type, rpd.value.instance, rpd.value.action);
1885 PermDAO.Data createPerm = null; // if not null, create first
1886 if (rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1887 if (trans.requested(force)) {
1888 // Remove roles from perm data object so we just create the perm here
1889 createPerm = rpd.value;
1890 createPerm.roles.clear();
1892 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1893 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1896 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1897 return Result.err(Status.ERR_ConflictAlreadyExists,
1898 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1899 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1900 rrd.value.ns,rrd.value.name
1906 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1909 public String get() {
1910 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1911 " to Role [" + rrd.value.fullName() + "]";
1915 private Result<NsDAO.Data> nsd;
1917 public Result<?> mayChange() {
1919 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1924 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rpd.value.ns);
1925 if (nsr.notOKorIsEmpty()) {
1926 return Result.err(nsr);
1930 Result<String> rfc = func.createFuture(trans,fd.value,
1931 rpd.value.fullPerm(),
1936 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
1942 return Result.err(rfc);
1944 case Status.ACC_Now:
1945 Result<Void> rv = null;
1946 if (createPerm!=null) {// has been validated for creating
1947 rv = func.createPerm(trans, createPerm, false);
1949 if (rv==null || rv.isOK()) {
1950 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
1954 return Result.err(fd);
1960 * Delete Perms from Roles (UnGrant)
1962 * @param roleFullName
1967 path = "/authz/role/:role/perm",
1968 params = {"role|string|true"},
1970 errorCodes = {404,406},
1971 text = { "Ungrant a permission from Role :role" }
1975 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
1976 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1977 if (updt.notOKorIsEmpty()) {
1978 return Result.err(updt);
1980 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1981 if (rrd.notOKorIsEmpty()) {
1982 return Result.err(rrd);
1985 final ServiceValidator v = new ServiceValidator();
1986 if (v.nullOrBlank(updt.value)
1987 .nullOrBlank(rrd.value)
1989 return Result.err(Status.ERR_BadData,v.errs());
1992 return delPermFromRole(trans, updt.value,rrd.value, rreq);
1995 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
1996 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, pdd.ns, pdd.type,
1997 pdd.instance, pdd.action);
1999 if (rlpd.notOKorIsEmpty()) {
2000 return Result.err(Status.ERR_PermissionNotFound,
2001 "Permission [%s.%s|%s|%s] does not exist",
2002 pdd.ns,pdd.type,pdd.instance,pdd.action);
2005 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
2008 public String get() {
2009 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
2010 " from Role [" + rdd.fullName() + "]";
2014 private Result<NsDAO.Data> nsd;
2016 public Result<?> mayChange() {
2018 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2023 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pdd.ns);
2024 if (nsr.notOKorIsEmpty()) {
2025 return Result.err(nsr);
2029 Result<String> rfc = func.createFuture(trans,fd.value,
2036 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2042 return Result.err(rfc);
2044 case Status.ACC_Now:
2045 return func.delPermFromRole(trans, rdd, pdd, false);
2047 return Result.err(fd);
2054 path = "/authz/role/:role/perm/:type/:instance/:action",
2055 params = {"role|string|true",
2056 "perm type|string|true",
2057 "perm instance|string|true",
2058 "perm action|string|true"
2061 errorCodes = {404,406},
2062 text = { "Ungrant a single permission from Role :role with direct key" }
2066 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2067 Result<Data> rpns = ques.deriveNs(trans, type);
2068 if (rpns.notOKorIsEmpty()) {
2069 return Result.err(rpns);
2072 final Validator v = new ServiceValidator();
2074 .permType(rpns.value.name,rpns.value.parent)
2075 .permInstance(instance)
2078 return Result.err(Status.ERR_BadData,v.errs());
2081 Result<Data> rrns = ques.deriveNs(trans, role);
2082 if (rrns.notOKorIsEmpty()) {
2083 return Result.err(rrns);
2086 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, rrns.value.parent, rrns.value.name);
2087 if (rrd.notOKorIsEmpty()) {
2088 return Result.err(rrd);
2091 final Result<List<PermDAO.Data>> rpd = ques.permDAO().read(trans, rpns.value.parent, rpns.value.name, instance, action);
2092 if (rpd.notOKorIsEmpty()) {
2093 return Result.err(rpd);
2097 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2102 path = "/authz/role/:role",
2103 params = {"role|string|true"},
2105 errorCodes = {404,406},
2106 text = { "Delete the Role named :role"}
2110 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2111 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2112 if (rrdd.isOKhasData()) {
2113 final ServiceValidator v = new ServiceValidator();
2114 if (v.nullOrBlank(rrdd.value).err()) {
2115 return Result.err(Status.ERR_BadData,v.errs());
2117 return func.deleteRole(trans, rrdd.value, false, false);
2119 return Result.err(rrdd);
2125 path = "/authz/role",
2128 errorCodes = { 404,406 },
2129 text = { "Delete the Role referenced by RoleKey",
2130 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2131 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2132 "as a query parameter.",
2133 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2137 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2138 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2139 final ServiceValidator v = new ServiceValidator();
2141 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2143 if (v.nullOrBlank(rd.value).err()) {
2144 return Result.err(Status.ERR_BadData,v.errs());
2146 final RoleDAO.Data role = rd.value;
2147 if (ques.roleDAO().read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2148 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2151 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2152 () -> "Delete Role [" + role.fullName() + ']'
2153 + " and all attached user roles",
2155 private Result<NsDAO.Data> nsd;
2157 public Result<?> mayChange() {
2159 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2167 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
2168 if (nsr.notOKorIsEmpty()) {
2169 return Result.err(nsr);
2172 Result<String> rfc = func.createFuture(trans, fd.value,
2173 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2175 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2179 return Result.err(rfc);
2181 case Status.ACC_Now:
2182 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2184 return Result.err(fd);
2189 /***********************************
2191 ***********************************/
2192 private class MayCreateCred implements MayChange {
2193 private Result<NsDAO.Data> nsd;
2194 private AuthzTrans trans;
2195 private CredDAO.Data cred;
2196 private Executor exec;
2198 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2205 public Result<?> mayChange() {
2207 nsd = ques.validNSOfDomain(trans, cred.id);
2209 // is Ns of CredID valid?
2213 if (trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2216 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2217 if (rmc.isOKhasData()) {
2221 } catch (Exception e) {
2222 trans.warn().log(e);
2225 trans.warn().log(nsd.errorString());
2227 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2231 private class MayChangeCred implements MayChange {
2233 private Result<NsDAO.Data> nsd;
2234 private AuthzTrans trans;
2235 private CredDAO.Data cred;
2236 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
2242 public Result<?> mayChange() {
2243 // User can change himself (but not create)
2244 if (trans.user().equals(cred.id)) {
2248 nsd = ques.validNSOfDomain(trans, cred.id);
2250 // Get the Namespace
2252 if (ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
2255 String user[] = Split.split('.',trans.user());
2256 if (user.length>2) {
2257 String company = user[user.length-1] + '.' + user[user.length-2];
2258 if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) {
2263 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
2268 private final long DAY_IN_MILLIS = 24*3600*1000L;
2272 path = "/authn/cred",
2275 errorCodes = {403,404,406,409},
2276 text = { "A credential consists of:",
2277 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2278 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2279 "AB1234@myapp.att.com</li>",
2280 "<li>password - Company Policy Compliant Password</li></ul>",
2281 "Note: AAF does support multiple credentials with the same ID.",
2282 "Check with your organization if you have this implemented."
2286 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2287 final String cmdDescription = ("Create User Credential");
2288 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2291 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2292 if (rcred.isOKhasData()) {
2293 rcred = ques.userCredSetup(trans, rcred.value);
2295 final ServiceValidator v = new ServiceValidator();
2297 if (v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2298 return Result.err(Status.ERR_BadData,v.errs());
2302 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2303 Identity mechID = null;
2304 Organization org = trans.org();
2306 mechID = org.getIdentity(trans, rcred.value.id);
2307 } catch (Exception e1) {
2308 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2310 if (mechID==null || !mechID.isFound()) {
2311 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2314 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2315 if (nsr.notOKorIsEmpty()) {
2316 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2320 boolean firstID = false;
2323 CassExecutor exec = new CassExecutor(trans, func);
2324 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2325 if (rlcd.isOKhasData()) {
2326 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2327 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2330 for (CredDAO.Data curr : rlcd.value) {
2331 // May not use the same password in the list
2332 // Note: ASPR specifies character differences, but we don't actually store the
2333 // password to validate char differences.
2335 // byte[] rawCred = rcred.value.type==CredDAO.RAW?null:;
2337 rb = ques.userCredCheck(trans, curr, rcred.value.cred.array());
2339 return Result.err(rb);
2340 } else if (rb.value){
2341 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2342 } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
2343 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
2348 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2349 String theMechID = rcred.value.id;
2350 Boolean otherMechIDs = false;
2351 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2352 for (CredDAO.Data cd : ques.credDAO().readNS(trans,nsr.value.get(0).name).value) {
2353 if (!cd.id.equals(theMechID)) {
2354 otherMechIDs = true;
2359 // We can say "ID does not exist" here
2360 if ((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2361 return Result.err(Status.ERR_Denied, reason);
2364 } catch (Exception e) {
2365 return Result.err(e);
2369 mc = new MayCreateCred(trans, rcred.value, exec);
2371 final CredDAO.Data cdd = rcred.value;
2372 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2375 public String get() {
2376 return cmdDescription + " [" +
2379 + cdd.expires + ']';
2386 Result<String> rfc = func.createFuture(trans, fd.value,
2387 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2388 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2390 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2392 Integer.toString(rcred.value.type),
2393 rcred.value.expires.toString());
2395 return Result.err(rfc);
2397 case Status.ACC_Now:
2400 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
2401 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
2402 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
2403 // Note, we only do this on First time, because of possibility of
2404 // prematurely expiring a production id
2405 if (admins.isOKhasData() && !admins.value.contains(trans.user())) {
2406 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2409 } catch (Exception e) {
2410 trans.error().log(e, "While setting expiration to TempPassword");
2413 Result<?>udr = ques.credDAO().create(trans, rcred.value);
2417 return Result.err(udr);
2419 return Result.err(fd);
2423 return Result.err(rcred);
2432 path = "/authn/creds/ns/:ns",
2433 params = {"ns|string|true"},
2435 errorCodes = {403,404,406},
2436 text = { "Return all IDs in Namespace :ns"
2440 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2441 final Validator v = new ServiceValidator();
2442 if (v.ns(ns).err()) {
2443 return Result.err(Status.ERR_BadData,v.errs());
2446 // check if user is allowed to view NS
2447 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2449 return Result.err(rnd);
2451 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2453 return Result.err(rnd);
2456 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2458 USERS users = mapper.newInstance(API.USERS);
2459 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readNS(trans, ns);
2462 if (!rlcd.isEmpty()) {
2463 return mapper.cred(rlcd.value, users);
2465 return Result.ok(users);
2467 return Result.err(rlcd);
2477 path = "/authn/creds/id/:ns",
2478 params = {"id|string|true"},
2480 errorCodes = {403,404,406},
2481 text = { "Return all IDs in for ID"
2482 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2486 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2487 final Validator v = new ServiceValidator();
2488 if (v.nullOrBlank("ID",id).err()) {
2489 return Result.err(Status.ERR_BadData,v.errs());
2492 String ns = Question.domain2ns(id);
2493 // check if user is allowed to view NS
2494 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2496 return Result.err(rnd);
2498 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2500 return Result.err(rnd);
2503 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2505 USERS users = mapper.newInstance(API.USERS);
2506 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, id);
2509 if (!rlcd.isEmpty()) {
2510 return mapper.cred(rlcd.value, users);
2512 return Result.ok(users);
2514 return Result.err(rlcd);
2524 path = "/authn/certs/id/:id",
2525 params = {"id|string|true"},
2527 errorCodes = {403,404,406},
2528 text = { "Return Cert Info for ID"
2532 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2533 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2535 CERTS certs = mapper.newInstance(API.CERTS);
2536 Result<List<CertDAO.Data>> rlcd = ques.certDAO().readID(trans, id);
2539 if (!rlcd.isEmpty()) {
2540 return mapper.cert(rlcd.value, certs);
2542 return Result.ok(certs);
2544 return Result.err(rlcd);
2554 path = "/authn/cred",
2557 errorCodes = {300,403,404,406},
2558 text = { "Reset a Credential Password. If multiple credentials exist for this",
2559 "ID, you will need to specify which entry you are resetting in the",
2560 "CredRequest object"
2564 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
2565 final String cmdDescription = "Update User Credential";
2566 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2568 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2569 if (rcred.isOKhasData()) {
2570 rcred = ques.userCredSetup(trans, rcred.value);
2572 final ServiceValidator v = new ServiceValidator();
2574 if (v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2575 return Result.err(Status.ERR_BadData,v.errs());
2577 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2578 if (rlcd.notOKorIsEmpty()) {
2579 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2582 MayChange mc = new MayChangeCred(trans, rcred.value);
2583 Result<?> rmc = mc.mayChange();
2585 return Result.err(rmc);
2588 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2590 return Result.err(ri);
2592 int entry = ri.value;
2595 final CredDAO.Data cred = rcred.value;
2597 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2600 public String get() {
2601 return cmdDescription + " [" +
2604 + cred.expires + ']';
2609 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2610 if (nsr.notOKorIsEmpty()) {
2611 return Result.err(nsr);
2616 Result<String> rfc = func.createFuture(trans, fd.value,
2617 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2618 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2620 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2622 Integer.toString(rcred.value.type),
2623 rcred.value.expires.toString());
2625 return Result.err(rfc);
2627 case Status.ACC_Now:
2628 Result<?>udr = null;
2629 // If we are Resetting Password on behalf of someone else (am not the Admin)
2630 // use TempPassword Expiration time.
2632 if (ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2633 exp = Expiration.Password;
2635 exp = Expiration.TempPassword;
2638 Organization org = trans.org();
2639 CredDAO.Data current = rlcd.value.get(entry);
2640 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2641 if (current.expires.equals(rcred.value.expires)
2642 && rlcd.value.get(entry).type==rcred.value.type) {
2643 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2644 gc = Chrono.firstMomentOfDay(gc);
2645 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2646 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2648 rcred.value.expires = org.expiration(null,exp).getTime();
2651 udr = ques.credDAO().create(trans, rcred.value);
2653 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2659 return Result.err(udr);
2661 return Result.err(fd);
2664 return Result.err(rcred);
2672 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
2674 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
2676 if (lcd.size() > 1) {
2677 String inputOption = cr.getEntry();
2678 if (inputOption == null) {
2679 String message = selectCredFromList(lcd, false);
2680 Object[] variables = buildVariables(lcd);
2681 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2683 entry = Integer.parseInt(inputOption) - 1;
2685 if (entry < 0 || entry >= lcd.size()) {
2686 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2689 return Result.ok(entry);
2694 path = "/authn/cred/:days",
2695 params = {"days|string|true"},
2697 errorCodes = {300,403,404,406},
2698 text = { "Extend a Credential Expiration Date. The intention of this API is",
2699 "to avoid an outage in PROD due to a Credential expiring before it",
2700 "can be configured correctly. Measures are being put in place ",
2701 "so that this is not abused."
2705 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2706 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2708 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2709 Organization org = trans.org();
2710 final ServiceValidator v = new ServiceValidator();
2711 if (v.notOK(cred).err() ||
2712 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2713 v.user(org,cred.value.id).err()) {
2714 return Result.err(Status.ERR_BadData,v.errs());
2719 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2720 return Result.err(Status.ERR_Policy,reason);
2722 } catch (Exception e) {
2724 trans.error().log(e, msg="Could not contact Organization for User Validation");
2725 return Result.err(Status.ERR_Denied, msg);
2728 // Get the list of Cred Entries
2729 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2730 if (rlcd.notOKorIsEmpty()) {
2731 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2734 //Need to do the "Pick Entry" mechanism
2735 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2737 return Result.err(ri);
2740 CredDAO.Data found = rlcd.value.get(ri.value);
2741 CredDAO.Data cd = cred.value;
2742 // Copy over the cred
2744 cd.cred = found.cred;
2745 cd.other = found.other;
2746 cd.type = found.type;
2748 cd.notes = "Extended";
2749 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2752 cred = ques.credDAO().create(trans, cd);
2756 return Result.err(cred);
2762 private String[] buildVariables(List<CredDAO.Data> value) {
2763 // ensure credentials are sorted so we can fully automate Cred regression test
2764 Collections.sort(value, (cred1, cred2) -> cred1.expires.compareTo(cred2.expires));
2765 String [] vars = new String[value.size()+1];
2767 for (int i = 0; i < value.size(); i++) {
2768 vars[i+1] = value.get(i).id + " " + value.get(i).type
2769 + " |" + value.get(i).expires;
2774 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
2775 StringBuilder errMessage = new StringBuilder();
2776 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
2777 int numSpaces = value.get(0).id.length() - "Id".length();
2779 errMessage.append(userPrompt + '\n');
2780 errMessage.append(" Id");
2781 for (int i = 0; i < numSpaces; i++) {
2782 errMessage.append(' ');
2784 errMessage.append(" Type Expires" + '\n');
2785 for (int i=0;i<value.size();++i) {
2786 errMessage.append(" %s\n");
2788 errMessage.append("Run same command again with chosen entry as last parameter");
2790 return errMessage.toString();
2796 path = "/authn/cred",
2799 errorCodes = {300,403,404,406},
2800 text = { "Delete a Credential. If multiple credentials exist for this",
2801 "ID, you will need to specify which entry you are deleting in the",
2802 "CredRequest object."
2806 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2807 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2808 final Validator v = new ServiceValidator();
2809 if (v.nullOrBlank("cred", cred.value.id).err()) {
2810 return Result.err(Status.ERR_BadData,v.errs());
2813 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2814 if (rlcd.notOKorIsEmpty()) {
2815 // Empty Creds should have no user_roles.
2816 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2818 for (UserRoleDAO.Data data : rlurd.value) {
2819 ques.userRoleDAO().delete(trans, data, false);
2822 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2824 boolean isLastCred = rlcd.value.size()==1;
2826 MayChange mc = new MayChangeCred(trans,cred.value);
2827 Result<?> rmc = mc.mayChange();
2829 return Result.err(rmc);
2833 if (!trans.requested(force)) {
2834 if (rlcd.value.size() > 1) {
2835 CredRequest cr = (CredRequest)from;
2836 String inputOption = cr.getEntry();
2837 if (inputOption == null) {
2838 String message = selectCredFromList(rlcd.value, true);
2839 Object[] variables = buildVariables(rlcd.value);
2840 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2843 if (inputOption.length()>5) { // should be a date
2844 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2846 for (CredDAO.Data cd : rlcd.value) {
2847 if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2853 entry = Integer.parseInt(inputOption) - 1;
2855 } catch (NullPointerException e) {
2856 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2857 } catch (NumberFormatException e) {
2858 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2861 isLastCred = (entry==-1)?true:false;
2865 if (entry < -1 || entry >= rlcd.value.size()) {
2866 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2870 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2871 () -> "Delete Credential [" +
2876 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
2877 if (nsr.notOKorIsEmpty()) {
2878 return Result.err(nsr);
2883 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2884 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2887 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2889 return Result.err(rfc);
2891 case Status.ACC_Now:
2892 Result<?>udr = null;
2893 if (!trans.requested(force)) {
2894 if (entry<0 || entry >= rlcd.value.size()) {
2895 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
2897 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2899 for (CredDAO.Data curr : rlcd.value) {
2900 udr = ques.credDAO().delete(trans, curr, false);
2902 return Result.err(udr);
2907 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2909 for (UserRoleDAO.Data data : rlurd.value) {
2910 ques.userRoleDAO().delete(trans, data, false);
2915 return Result.err(Result.ERR_NotFound,"No User Data found");
2920 return Result.err(udr);
2922 return Result.err(fd);
2929 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
2930 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
2932 // Note: Mapper assigns RAW type
2933 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
2934 if (data.notOKorIsEmpty()) {
2935 return Result.err(data);
2937 CredDAO.Data cred = data.value; // of the Mapped Cred
2938 if (cred.cred==null) {
2939 return Result.err(Result.ERR_BadData,"No Password");
2941 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
2944 } catch (DAOException e) {
2945 trans.error().log(e,"Error looking up cred");
2946 return Result.err(Status.ERR_Denied,"Credential does not match");
2954 path = "/authn/basicAuth",
2957 errorCodes = { 403 },
2958 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
2959 + "Use /authn/validate instead\n"
2960 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
2961 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
2962 + "security, and 403 if it does not." }
2964 private void basicAuth() {
2965 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
2970 path = "/authn/validate",
2973 errorCodes = { 403 },
2974 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
2975 + "do more than BasicAuth as Credential types exp" }
2978 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
2979 //TODO how to make sure people don't use this in browsers? Do we care?
2980 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
2982 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
2983 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
2984 // Note: Only want to log problem, don't want to send back to end user
2988 trans.audit().log(rq.errorString());
2990 } catch (Exception e) {
2991 trans.warn().log(e);
2995 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
2998 /***********************************
3000 ***********************************/
3003 path = "/authz/userRole",
3006 errorCodes = {403,404,406,409},
3007 text = { "Create a UserRole relationship (add User to Role)",
3008 "A UserRole is an object Representation of membership of a Role for limited time.",
3009 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
3010 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
3011 "before Expirations expire. Namespace owners will be notified by email."
3015 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3016 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3018 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3019 if (urr.notOKorIsEmpty()) {
3020 return Result.err(urr);
3022 final UserRoleDAO.Data userRole = urr.value;
3024 final ServiceValidator v = new ServiceValidator();
3025 if (v.user_role(userRole).err() ||
3026 v.user(trans.org(), userRole.user).err()) {
3027 return Result.err(Status.ERR_BadData,v.errs());
3032 // Check if user can change first
3033 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3034 () -> "Add User [" + userRole.user + "] to Role [" +
3038 private Result<NsDAO.Data> nsd;
3040 public Result<?> mayChange() {
3042 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3043 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3048 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3049 if (nsr.notOKorIsEmpty()) {
3050 return Result.err(nsr);
3055 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3056 userRole.user, nsr.value, FUTURE_OP.C);
3058 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3063 return Result.err(rfc);
3065 case Status.ACC_Now:
3066 return func.addUserRole(trans, userRole);
3068 return Result.err(fd);
3076 * getUserRolesByRole
3080 path = "/authz/userRoles/role/:role",
3081 params = {"role|string|true"},
3083 errorCodes = {404,406},
3084 text = { "List all Users that are attached to Role specified in :role",
3088 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3089 final Validator v = new ServiceValidator();
3090 if (v.nullOrBlank("Role",role).err()) {
3091 return Result.err(Status.ERR_BadData,v.errs());
3094 Result<RoleDAO.Data> rrdd;
3095 rrdd = RoleDAO.Data.decode(trans,ques,role);
3097 return Result.err(rrdd);
3099 // May Requester see result?
3100 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3102 return Result.err(ns);
3105 // boolean filter = true;
3106 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3109 // Get list of roles per user, then add to Roles as we go
3110 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3111 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3113 for (UserRoleDAO.Data data : rlurd.value) {
3118 @SuppressWarnings("unchecked")
3119 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3120 // Checked for permission
3121 mapper.userRoles(trans, userSet, users);
3122 return Result.ok(users);
3125 * getUserRolesByRole
3129 path = "/authz/userRoles/user/:user",
3130 params = {"role|string|true"},
3132 errorCodes = {404,406},
3133 text = { "List all UserRoles for :user",
3137 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3138 final Validator v = new ServiceValidator();
3139 if (v.nullOrBlank("User",user).err()) {
3140 return Result.err(Status.ERR_BadData,v.errs());
3143 // Get list of roles per user, then add to Roles as we go
3144 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
3145 if (rlurd.notOK()) {
3146 return Result.err(rlurd);
3151 * 2) is User's Supervisor
3152 * 3) Has special global access =read permission
3154 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3157 String callingUser = trans.getUserPrincipal().getName();
3158 NsDAO.Data ndd = new NsDAO.Data();
3160 if (user.equals(callingUser)) {
3163 Organization org = trans.org();
3165 Identity orgID = org.getIdentity(trans, user);
3166 Identity manager = orgID==null?null:orgID.responsibleTo();
3167 if (orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3169 } else if (ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3174 } catch (OrganizationException e) {
3180 List<UserRoleDAO.Data> content;
3182 content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos
3184 for (UserRoleDAO.Data data : rlurd.value) {
3186 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3193 content = rlurd.value;
3197 @SuppressWarnings("unchecked")
3198 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3199 // Checked for permission
3200 mapper.userRoles(trans, content, users);
3201 return Result.ok(users);
3209 path = "/authz/userRole/extend/:user/:role",
3210 params = { "user|string|true",
3214 errorCodes = {403,404,406},
3215 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3216 "Requestor must be allowed to modify the role"
3220 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3221 Organization org = trans.org();
3222 final ServiceValidator v = new ServiceValidator();
3223 if (v.user(org, user)
3226 return Result.err(Status.ERR_BadData,v.errs());
3229 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3231 return Result.err(rrdd);
3234 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3235 boolean mayNotChange;
3236 if ((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3237 return Result.err(rcr);
3240 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO().read(trans, user,role);
3242 return Result.err(rr);
3244 for (UserRoleDAO.Data userRole : rr.value) {
3245 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3246 FutureDAO.Data fto = new FutureDAO.Data();
3247 fto.target=UserRoleDAO.TABLE;
3248 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3249 GregorianCalendar now = new GregorianCalendar();
3250 fto.start = now.getTime();
3251 fto.expires = org.expiration(now, Expiration.Future).getTime();
3253 fto.construct = userRole.bytify();
3254 } catch (IOException e) {
3255 trans.error().log(e, "Error while bytifying UserRole for Future");
3256 return Result.err(e);
3259 Result<String> rfc = func.createFuture(trans, fto,
3260 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3262 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3266 return Result.err(rfc);
3269 return func.extendUserRole(trans, userRole, false);
3272 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3277 path = "/authz/userRole/:user/:role",
3278 params = { "user|string|true",
3282 errorCodes = {403,404,406},
3283 text = { "Remove Role :role from User :user."
3287 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3288 Validator val = new ServiceValidator();
3289 if (val.nullOrBlank("User", usr)
3290 .nullOrBlank("Role", role).err()) {
3291 return Result.err(Status.ERR_BadData, val.errs());
3294 boolean mayNotChange;
3295 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3297 return Result.err(rrdd);
3300 RoleDAO.Data rdd = rrdd.value;
3301 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3303 // Make sure we don't delete the last owner of valid NS
3304 if (rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3305 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3308 if (mayNotChange=rns.notOK()) {
3309 if (!trans.requested(future)) {
3310 return Result.err(rns);
3314 Result<List<UserRoleDAO.Data>> rulr;
3315 if ((rulr=ques.userRoleDAO().read(trans, usr, role)).notOKorIsEmpty()) {
3316 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3317 + "Assigned to the Role [ " + role + " ]");
3320 UserRoleDAO.Data userRole = rulr.value.get(0);
3321 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3322 FutureDAO.Data fto = new FutureDAO.Data();
3323 fto.target=UserRoleDAO.TABLE;
3324 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3325 GregorianCalendar now = new GregorianCalendar();
3326 fto.start = now.getTime();
3327 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3329 Result<String> rfc = func.createFuture(trans, fto,
3330 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3332 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3336 return Result.err(rfc);
3339 return ques.userRoleDAO().delete(trans, rulr.value.get(0), false);
3345 path = "/authz/userRole/:user/:role",
3346 params = {"user|string|true",
3347 "role|string|true"},
3349 errorCodes = {403,404,406},
3350 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3354 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3355 final Validator v = new ServiceValidator();
3356 if (v.role(role).nullOrBlank("User", user).err()) {
3357 return Result.err(Status.ERR_BadData,v.errs());
3360 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3361 // if (ns.notOK()) return Result.err(ns);
3363 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3364 // May calling user see by virtue of the Role
3365 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3367 return Result.err(rrdd);
3369 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3371 return Result.err(rnd);
3374 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3375 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readUserInRole(trans, user, role);
3377 for (UserRoleDAO.Data data : rlurd.value) {
3382 @SuppressWarnings("unchecked")
3383 USERS users = (USERS) mapper.newInstance(API.USERS);
3384 mapper.users(trans, userSet, users);
3385 return Result.ok(users);
3390 path = "/authz/users/role/:role",
3391 params = {"user|string|true",
3392 "role|string|true"},
3394 errorCodes = {403,404,406},
3395 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3399 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3400 final Validator v = new ServiceValidator();
3401 if (v.nullOrBlank("Role",role).err()) {
3402 return Result.err(Status.ERR_BadData,v.errs());
3405 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3406 // if (ns.notOK()) return Result.err(ns);
3408 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3409 // May calling user see by virtue of the Role
3410 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3412 return Result.err(rrdd);
3415 boolean contactOnly = false;
3416 // Allow the request of any valid user to find the contact of the NS (Owner)
3417 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3419 if (Question.OWNER.equals(rrdd.value.name)) {
3422 return Result.err(rnd);
3426 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3427 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3429 for (UserRoleDAO.Data data : rlurd.value) {
3430 if (contactOnly) { //scrub data
3431 // Can't change actual object, or will mess up the cache.
3432 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3434 scrub.rname = data.rname;
3435 scrub.role = data.role;
3436 scrub.user = data.user;
3444 @SuppressWarnings("unchecked")
3445 USERS users = (USERS) mapper.newInstance(API.USERS);
3446 mapper.users(trans, userSet, users);
3447 return Result.ok(users);
3451 * getUsersByPermission
3455 path = "/authz/users/perm/:type/:instance/:action",
3456 params = { "type|string|true",
3457 "instance|string|true",
3458 "action|string|true"
3461 errorCodes = {404,406},
3462 text = { "List all Users that have Permission specified by :type :instance :action",
3466 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3467 final Validator v = new ServiceValidator();
3468 if (v.nullOrBlank("Type",type)
3469 .nullOrBlank("Instance",instance)
3470 .nullOrBlank("Action",action)
3472 return Result.err(Status.ERR_BadData,v.errs());
3475 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3477 return Result.err(nss);
3480 Result<List<NsDAO.Data>> nsd = ques.nsDAO().read(trans, nss.value.ns);
3482 return Result.err(nsd);
3485 boolean allInstance = ASTERIX.equals(instance);
3486 boolean allAction = ASTERIX.equals(action);
3487 // Get list of roles per Permission,
3488 // Then loop through Roles to get Users
3489 // Note: Use Sets to avoid processing or responding with Duplicates
3490 Set<String> roleUsed = new HashSet<>();
3491 Set<UserRoleDAO.Data> userSet = new HashSet<>();
3493 if (!nss.isEmpty()) {
3494 Result<List<PermDAO.Data>> rlp = ques.permDAO().readByType(trans, nss.value.ns, nss.value.name);
3495 if (rlp.isOKhasData()) {
3496 for (PermDAO.Data pd : rlp.value) {
3497 if ((allInstance || pd.instance.equals(instance)) &&
3498 (allAction || pd.action.equals(action))) {
3499 if (ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3500 for (String role : pd.roles) {
3501 if (!roleUsed.contains(role)) { // avoid evaluating Role many times
3503 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role.replace('|', '.'));
3504 if (rlurd.isOKhasData()) {
3505 for (UserRoleDAO.Data urd : rlurd.value) {
3516 @SuppressWarnings("unchecked")
3517 USERS users = (USERS) mapper.newInstance(API.USERS);
3518 mapper.users(trans, userSet, users);
3519 return Result.ok(users);
3522 /***********************************
3524 ***********************************/
3526 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3527 final Validator v = new ServiceValidator();
3528 if (v.nullOrBlank("User",user).err()) {
3529 return Result.err(Status.ERR_BadData,v.errs());
3532 Result<NsDAO.Data> rnd;
3533 // Users may look at their own data
3534 if (trans.user().equals(user)) {
3535 // Users may look at their own data
3537 int at = user.indexOf('@');
3538 if (at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3539 NsDAO.Data nsd = new NsDAO.Data();
3540 nsd.name = Question.domain2ns(user);
3541 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3543 return Result.err(rnd);
3546 rnd = ques.validNSOfDomain(trans, user);
3548 return Result.err(rnd);
3551 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3553 return Result.err(rnd);
3557 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readByUser(trans, user, yyyymm);
3559 return Result.err(resp);
3561 return mapper.history(trans, resp.value,sort);
3565 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3566 final Validator v = new ServiceValidator();
3567 if (v.nullOrBlank("Role",role).err()) {
3568 return Result.err(Status.ERR_BadData,v.errs());
3571 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3573 return Result.err(rrdd);
3576 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3578 return Result.err(rnd);
3580 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, role, "role", yyyymm);
3582 return Result.err(resp);
3584 return mapper.history(trans, resp.value,sort);
3588 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3589 final Validator v = new ServiceValidator();
3590 if (v.nullOrBlank("Type",type)
3592 return Result.err(Status.ERR_BadData,v.errs());
3595 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3596 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3598 return Result.err(rnd);
3601 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3603 return Result.err(rnd);
3605 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3607 return Result.err(resp);
3609 return mapper.history(trans, resp.value,sort);
3613 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3614 final Validator v = new ServiceValidator();
3615 if (v.nullOrBlank("NS",ns)
3617 return Result.err(Status.ERR_BadData,v.errs());
3620 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3622 return Result.err(rnd);
3624 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3626 return Result.err(rnd);
3629 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, ns, "ns", yyyymm);
3631 return Result.err(resp);
3633 return mapper.history(trans, resp.value,sort);
3636 /***********************************
3638 ***********************************/
3640 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3641 return createOrUpdateDelegate(trans, base, Question.Access.create);
3645 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3646 return createOrUpdateDelegate(trans, base, Question.Access.write);
3650 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3651 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3652 final ServiceValidator v = new ServiceValidator();
3653 if (v.delegate(trans.org(),rd).err()) {
3654 return Result.err(Status.ERR_BadData,v.errs());
3657 final DelegateDAO.Data dd = rd.value;
3659 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO().read(trans, dd);
3660 if (access==Access.create && ddr.isOKhasData()) {
3661 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3662 } else if (access!=Access.create && ddr.notOKorIsEmpty()) {
3663 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3665 Result<Void> rv = ques.mayUser(trans, dd, access);
3670 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3672 StringBuilder sb = new StringBuilder();
3673 sb.append(access.name());
3674 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3675 sb.append("Delegate ");
3676 sb.append(access==Access.create?"[":"to [");
3677 sb.append(rd.value.delegate);
3678 sb.append("] for [");
3679 sb.append(rd.value.user);
3681 return sb.toString();
3684 return Result.ok(); // Validate in code above
3689 Result<String> rfc = func.createFuture(trans, fd.value,
3690 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3692 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3695 return Result.err(rfc);
3697 case Status.ACC_Now:
3698 if (access==Access.create) {
3699 Result<DelegateDAO.Data> rdr = ques.delegateDAO().create(trans, dd);
3703 return Result.err(rdr);
3706 return ques.delegateDAO().update(trans, dd);
3709 return Result.err(fd);
3714 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3715 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3716 final Validator v = new ServiceValidator();
3717 if (v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3718 return Result.err(Status.ERR_BadData,v.errs());
3721 Result<List<DelegateDAO.Data>> ddl;
3722 if ((ddl=ques.delegateDAO().read(trans, rd.value)).notOKorIsEmpty()) {
3723 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3725 final DelegateDAO.Data dd = ddl.value.get(0);
3726 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3731 return ques.delegateDAO().delete(trans, dd, false);
3735 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3736 DelegateDAO.Data dd = new DelegateDAO.Data();
3737 final Validator v = new ServiceValidator();
3738 if (v.nullOrBlank("User", userName).err()) {
3739 return Result.err(Status.ERR_BadData,v.errs());
3742 Result<List<DelegateDAO.Data>> ddl;
3743 if ((ddl=ques.delegateDAO().read(trans, dd)).notOKorIsEmpty()) {
3744 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3746 dd = ddl.value.get(0);
3747 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3752 return ques.delegateDAO().delete(trans, dd, false);
3756 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
3757 final Validator v = new ServiceValidator();
3758 if (v.nullOrBlank("User", user).err()) {
3759 return Result.err(Status.ERR_BadData,v.errs());
3762 DelegateDAO.Data ddd = new DelegateDAO.Data();
3764 ddd.delegate = null;
3765 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3767 return Result.err(rv);
3770 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
3772 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().read(trans, user);
3774 if (dbDelgs.isOKhasData()) {
3775 return mapper.delegate(dbDelgs.value);
3777 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
3785 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
3786 final Validator v = new ServiceValidator();
3787 if (v.nullOrBlank("Delegate", delegate).err()) {
3788 return Result.err(Status.ERR_BadData,v.errs());
3791 DelegateDAO.Data ddd = new DelegateDAO.Data();
3792 ddd.user = delegate;
3793 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3795 return Result.err(rv);
3798 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
3800 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().readByDelegate(trans, delegate);
3802 if (dbDelgs.isOKhasData()) {
3803 return mapper.delegate(dbDelgs.value);
3805 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
3812 /***********************************
3814 ***********************************/
3815 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
3817 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
3818 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
3820 return Result.err(rlad);
3822 int numApprs = rlad.value.size();
3824 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
3826 int numProcessed = 0;
3827 String user = trans.user();
3829 Result<List<ApprovalDAO.Data>> curr;
3830 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
3831 for (ApprovalDAO.Data updt : rlad.value) {
3832 if (updt.ticket!=null) {
3833 curr = ques.approvalDAO().readByTicket(trans, updt.ticket);
3834 if (curr.isOKhasData()) {
3835 final List<ApprovalDAO.Data> add = curr.value;
3836 // Store a Pre-Lookup
3837 apprByTicket = (trans1, noop) -> add;
3839 } else if (updt.id!=null) {
3840 curr = ques.approvalDAO().read(trans, updt);
3841 } else if (updt.approver!=null) {
3842 curr = ques.approvalDAO().readByApprover(trans, updt.approver);
3844 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
3847 if (curr.isOKhasData()) {
3848 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<>();
3849 Map<UUID, FutureDAO.Data> futureCache = new HashMap<>();
3850 FutureDAO.Data hasDeleted = new FutureDAO.Data();
3852 for (ApprovalDAO.Data cd : curr.value) {
3853 if ("pending".equals(cd.status)) {
3854 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
3856 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
3857 String delegator = cd.approver;
3858 if (updt.id!=null ||
3859 (updt.ticket!=null && user.equals(cd.approver)) ||
3860 (updt.ticket!=null && delegatedAction)) {
3861 if (updt.ticket.equals(cd.ticket)) {
3862 Changed ch = new Changed();
3863 cd.id = ch.changed(cd.id,updt.id);
3864 // cd.ticket = changed(cd.ticket,updt.ticket);
3865 cd.user = ch.changed(cd.user,updt.user);
3866 cd.approver = ch.changed(cd.approver,updt.approver);
3867 cd.type = ch.changed(cd.type,updt.type);
3868 cd.status = ch.changed(cd.status,updt.status);
3869 cd.memo = ch.changed(cd.memo,updt.memo);
3870 cd.operation = ch.changed(cd.operation,updt.operation);
3871 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
3872 // if (updt.status.equals("denied")) {
3873 // cd.last_notified = null;
3875 if (cd.ticket!=null) {
3876 FutureDAO.Data fdd = futureCache.get(cd.ticket);
3877 if (fdd==null) { // haven't processed ticket yet
3878 Result<FutureDAO.Data> rfdd = ques.futureDAO().readPrimKey(trans, cd.ticket);
3880 fdd = rfdd.value; // null is ok
3884 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
3886 if (fdd==hasDeleted) { // YES, by Object
3888 cd.status = "ticketDeleted";
3889 ch.hasChanged(true);
3891 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
3893 trans.info().printf("Approval Status %s is not actionable",cd.status);
3894 } else if (apprByTicket!=null) {
3895 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
3899 if (delegatedAction) {
3900 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
3902 futureCache.put(cd.ticket, hasDeleted);
3906 ch.hasChanged(true);
3907 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
3908 futureCache.put(cd.ticket, hasDeleted);
3913 trans.info().log(rv.toString());
3920 if (ch.hasChanged()) {
3921 ques.approvalDAO().update(trans, cd, true);
3930 if (numApprs==numProcessed) {
3933 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
3937 private static class Changed {
3938 private boolean hasChanged = false;
3940 public<T> T changed(T src, T proposed) {
3941 if (proposed==null || (src!=null && src.equals(proposed))) {
3948 public void hasChanged(boolean b) {
3952 public boolean hasChanged() {
3958 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
3959 final Validator v = new ServiceValidator();
3960 if (v.nullOrBlank("User", user).err()) {
3961 return Result.err(Status.ERR_BadData,v.errs());
3964 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByUser(trans, user);
3966 return mapper.approvals(rapd.value);
3968 return Result.err(rapd);
3973 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
3974 final Validator v = new ServiceValidator();
3975 if (v.nullOrBlank("Ticket", ticket).err()) {
3976 return Result.err(Status.ERR_BadData,v.errs());
3980 uuid = UUID.fromString(ticket);
3981 } catch (IllegalArgumentException e) {
3982 return Result.err(Status.ERR_BadData,e.getMessage());
3985 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByTicket(trans, uuid);
3987 return mapper.approvals(rapd.value);
3989 return Result.err(rapd);
3994 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
3995 final Validator v = new ServiceValidator();
3996 if (v.nullOrBlank("Approver", approver).err()) {
3997 return Result.err(Status.ERR_BadData,v.errs());
4000 List<ApprovalDAO.Data> listRapds = new ArrayList<>();
4002 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO().readByApprover(trans, approver);
4003 if (myRapd.notOK()) {
4004 return Result.err(myRapd);
4007 listRapds.addAll(myRapd.value);
4009 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO().readByDelegate(trans, approver);
4010 if (delegatedFor.isOK()) {
4011 for (DelegateDAO.Data dd : delegatedFor.value) {
4012 if (dd.expires.after(new Date())) {
4013 String delegator = dd.user;
4014 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByApprover(trans, delegator);
4016 for (ApprovalDAO.Data d : rapd.value) {
4017 if (!d.user.equals(trans.user())) {
4026 return mapper.approvals(listRapds);
4030 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4033 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4034 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4035 return ques.clearCache(trans,cname);
4037 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4038 trans.user(),ROOT_NS,CACHE,cname);
4042 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4045 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4046 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4047 Result<Void> v=null;
4048 for (int i: segment) {
4049 v=ques.cacheClear(trans,cname,i);
4055 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4056 trans.user(),ROOT_NS,CACHE,cname);
4060 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4063 public void dbReset(AuthzTrans trans) {
4064 ques.historyDAO().reportPerhapsReset(trans, null);