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.cached.CachedPermDAO;
51 import org.onap.aaf.auth.dao.cached.CachedRoleDAO;
52 import org.onap.aaf.auth.dao.cached.CachedUserRoleDAO;
53 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
54 import org.onap.aaf.auth.dao.cass.CertDAO;
55 import org.onap.aaf.auth.dao.cass.CredDAO;
56 import org.onap.aaf.auth.dao.cass.DelegateDAO;
57 import org.onap.aaf.auth.dao.cass.FutureDAO;
58 import org.onap.aaf.auth.dao.cass.HistoryDAO;
59 import org.onap.aaf.auth.dao.cass.Namespace;
60 import org.onap.aaf.auth.dao.cass.NsDAO;
61 import org.onap.aaf.auth.dao.cass.NsDAO.Data;
62 import org.onap.aaf.auth.dao.cass.NsSplit;
63 import org.onap.aaf.auth.dao.cass.NsType;
64 import org.onap.aaf.auth.dao.cass.PermDAO;
65 import org.onap.aaf.auth.dao.cass.RoleDAO;
66 import org.onap.aaf.auth.dao.cass.Status;
67 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
68 import org.onap.aaf.auth.dao.hl.CassExecutor;
69 import org.onap.aaf.auth.dao.hl.Function;
70 import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP;
71 import org.onap.aaf.auth.dao.hl.Function.Lookup;
72 import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
73 import org.onap.aaf.auth.dao.hl.Question;
74 import org.onap.aaf.auth.dao.hl.Question.Access;
75 import org.onap.aaf.auth.env.AuthzTrans;
76 import org.onap.aaf.auth.layer.Result;
77 import org.onap.aaf.auth.org.Executor;
78 import org.onap.aaf.auth.org.Organization;
79 import org.onap.aaf.auth.org.Organization.Expiration;
80 import org.onap.aaf.auth.org.Organization.Identity;
81 import org.onap.aaf.auth.org.Organization.Policy;
82 import org.onap.aaf.auth.org.OrganizationException;
83 import org.onap.aaf.auth.rserv.doc.ApiDoc;
84 import org.onap.aaf.auth.service.mapper.Mapper;
85 import org.onap.aaf.auth.service.mapper.Mapper.API;
86 import org.onap.aaf.auth.service.validation.ServiceValidator;
87 import org.onap.aaf.auth.validation.Validator;
88 import org.onap.aaf.cadi.principal.BasicPrincipal;
89 import org.onap.aaf.cadi.util.FQI;
90 import org.onap.aaf.misc.env.Env;
91 import org.onap.aaf.misc.env.TimeTaken;
92 import org.onap.aaf.misc.env.util.Chrono;
93 import org.onap.aaf.misc.env.util.Split;
95 import aaf.v2_0.CredRequest;
98 * AuthzCassServiceImpl implements AuthzCassService for
113 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
114 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
116 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
118 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
120 private static final String ASTERIX = "*";
121 private static final String CACHE = "cache";
122 private static final String ROOT_NS = Define.ROOT_NS();
123 private static final String ROOT_COMPANY = Define.ROOT_COMPANY();
125 private final Question ques;
126 private final Function func;
128 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
129 this.ques = question;
130 func = new Function(trans, question);
131 this.mapper = mapper;
135 /***********************************
137 ***********************************/
140 * @throws DAOException
141 * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
148 errorCodes = { 403,404,406,409 },
149 text = { "Namespace consists of: ",
150 "<ul><li>name - What you want to call this Namespace</li>",
151 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
152 "regarding this Namespace. Companies have Policies as to who may take on ",
153 "this Responsibility. Separate multiple identities with commas</li>",
154 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
155 "including creating Roles, Permissions and Credentials. Separate multiple ",
156 "identities with commas</li></ul>",
157 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
158 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
159 "be an admin of com.myCompany or com"
163 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
164 final Result<Namespace> rnamespace = mapper.ns(trans, from);
165 final ServiceValidator v = new ServiceValidator();
166 if (v.ns(rnamespace).err()) {
167 return Result.err(Status.ERR_BadData,v.errs());
169 final Namespace namespace = rnamespace.value;
170 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
171 if (parentNs.notOK()) {
172 return Result.err(parentNs);
175 // Note: Data validate occurs in func.createNS
176 if (namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
177 return func.createNS(trans, namespace, false);
180 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
183 public String get() {
184 return "Create Namespace [" + namespace.name + ']';
188 private Result<NsDAO.Data> rnd;
190 public Result<?> mayChange() {
192 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
199 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
201 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
203 return Result.err(rfc);
206 return func.createNS(trans, namespace, false);
208 return Result.err(fd);
214 path = "/authz/ns/:ns/admin/:id",
215 params = { "ns|string|true",
219 errorCodes = { 403,404,406,409 },
220 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
221 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
224 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
225 return func.addUserRole(trans, id, ns,Question.ADMIN);
230 path = "/authz/ns/:ns/admin/:id",
231 params = { "ns|string|true",
235 errorCodes = { 403,404 },
236 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
237 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
240 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
241 return func.delAdmin(trans,ns,id);
246 path = "/authz/ns/:ns/responsible/:id",
247 params = { "ns|string|true",
251 errorCodes = { 403,404,406,409 },
252 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
253 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
256 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
257 return func.addUserRole(trans,id,ns,Question.OWNER);
262 path = "/authz/ns/:ns/responsible/:id",
263 params = { "ns|string|true",
267 errorCodes = { 403,404 },
268 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
269 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
270 "Note: A namespace must have at least 1 responsible party"
274 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
275 return func.delOwner(trans,ns,id);
279 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
283 path = "/authz/ns/:ns/attrib/:key/:value",
284 params = { "ns|string|true",
286 "value|string|true"},
288 errorCodes = { 403,404,406,409 },
290 "Create an attribute in the Namespace",
291 "You must be given direct permission for key by AAF"
295 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
296 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
299 final Validator v = new ServiceValidator();
300 if (v.ns(ns).err() ||
302 v.value(value).err()) {
303 return Result.err(Status.ERR_BadData,v.errs());
306 // Check if exists already
307 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
308 if (rlnsd.notOKorIsEmpty()) {
309 return Result.err(rlnsd);
311 NsDAO.Data nsd = rlnsd.value.get(0);
313 // Check for Existence
314 if (nsd.attrib.get(key)!=null) {
315 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
318 // Check if User may put
319 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
320 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
321 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
325 nsd.attrib.put(key, value);
326 ques.nsDAO().dao().attribAdd(trans,ns,key,value);
327 ques.nsDAO().invalidate(trans, nsd);
336 path = "/authz/ns/attrib/:key",
337 params = { "key|string|true" },
339 errorCodes = { 403,404 },
341 "Read Attributes for Namespace"
345 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
347 final Validator v = new ServiceValidator();
348 if (v.nullOrBlank("Key",key).err()) {
349 return Result.err(Status.ERR_BadData,v.errs());
353 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
354 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
355 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
358 Result<Set<String>> rsd = ques.nsDAO().dao().readNsByAttrib(trans, key);
360 return Result.err(rsd);
362 return mapper().keys(rsd.value);
368 path = "/authz/ns/:ns/attrib/:key/:value",
369 params = { "ns|string|true",
372 errorCodes = { 403,404 },
374 "Update Value on an existing attribute in the Namespace",
375 "You must be given direct permission for key by AAF"
379 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
380 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
383 final Validator v = new ServiceValidator();
384 if (v.ns(ns).err() ||
386 v.value(value).err()) {
387 return Result.err(Status.ERR_BadData,v.errs());
390 // Check if exists already (NS must exist)
391 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
392 if (rlnsd.notOKorIsEmpty()) {
393 return Result.err(rlnsd);
395 NsDAO.Data nsd = rlnsd.value.get(0);
397 // Check for Existence
398 if (nsd.attrib.get(key)==null) {
399 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
402 // Check if User may put
403 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
404 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
405 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
409 nsd.attrib.put(key, value);
410 ques.nsDAO().invalidate(trans, nsd);
411 return ques.nsDAO().update(trans,nsd);
420 path = "/authz/ns/:ns/attrib/:key",
421 params = { "ns|string|true",
424 errorCodes = { 403,404 },
426 "Delete an attribute in the Namespace",
427 "You must be given direct permission for key by AAF"
431 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
432 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
435 final Validator v = new ServiceValidator();
436 if (v.nullOrBlank("NS",ns).err() ||
437 v.nullOrBlank("Key",key).err()) {
438 return Result.err(Status.ERR_BadData,v.errs());
441 // Check if exists already
442 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
443 if (rlnsd.notOKorIsEmpty()) {
444 return Result.err(rlnsd);
446 NsDAO.Data nsd = rlnsd.value.get(0);
448 // Check for Existence
449 if (nsd.attrib.get(key)==null) {
450 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
453 // Check if User may del
454 if (!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
455 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
459 nsd.attrib.remove(key);
460 ques.nsDAO().dao().attribRemove(trans,ns,key);
461 ques.nsDAO().invalidate(trans, nsd);
470 path = "/authz/nss/:id",
471 params = { "id|string|true" },
473 errorCodes = { 404,406 },
475 "Lists the Owner(s), Admin(s), Description, and Attributes of Namespace :id",
479 public Result<NSS> getNSbyName(AuthzTrans trans, String ns, boolean includeExpired) {
480 final Validator v = new ServiceValidator();
481 if (v.nullOrBlank("NS", ns).err()) {
482 return Result.err(Status.ERR_BadData,v.errs());
485 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, ns);
487 if (rlnd.isEmpty()) {
488 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
490 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
492 return Result.err(rnd);
496 Namespace namespace = new Namespace(rnd.value);
497 Result<List<String>> rd = func.getOwners(trans, namespace.name, includeExpired);
499 namespace.owner = rd.value;
501 rd = func.getAdmins(trans, namespace.name, includeExpired);
503 namespace.admin = rd.value;
506 NSS nss = mapper.newInstance(API.NSS);
507 return mapper.nss(trans, namespace, nss);
509 return Result.err(rlnd);
515 path = "/authz/nss/admin/:id",
516 params = { "id|string|true" },
518 errorCodes = { 403,404 },
519 text = { "Lists all Namespaces where Identity :id is an Admin",
520 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
524 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
525 final Validator v = new ServiceValidator();
526 if (v.nullOrBlank("User", user).err()) {
527 return Result.err(Status.ERR_BadData, v.errs());
530 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
532 return Result.err(rn);
535 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
537 NSS nss = mapper.newInstance(API.NSS);
538 // Note: "loadNamespace" already validates view of Namespace
539 return mapper.nss(trans, rn.value, nss);
544 path = "/authz/nss/either/:id",
545 params = { "id|string|true" },
547 errorCodes = { 403,404 },
548 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
549 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
553 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
554 final Validator v = new ServiceValidator();
555 if (v.nullOrBlank("User", user).err()) {
556 return Result.err(Status.ERR_BadData, v.errs());
559 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
561 return Result.err(rn);
564 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
566 NSS nss = mapper.newInstance(API.NSS);
567 // Note: "loadNamespace" already validates view of Namespace
568 return mapper.nss(trans, rn.value, nss);
571 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
572 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO().readByUser(trans, user);
573 if (urd.notOKorIsEmpty()) {
574 return Result.err(urd);
576 Map<String, Namespace> lm = new HashMap<>();
577 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<>();
578 for (UserRoleDAO.Data urdd : urd.value) {
580 if (endsWith==null || urdd.role.endsWith(endsWith)) {
581 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
582 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
584 Namespace namespace = lm.get(nsd.value.name);
585 if (namespace==null) {
586 namespace = new Namespace(nsd.value);
587 lm.put(namespace.name,namespace);
589 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
591 namespace.admin=rls.value;
594 rls = func.getOwners(trans, namespace.name, false);
596 namespace.owner=rls.value;
600 } else { // Shortened version. Only Namespace Info available from Role.
601 if (Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
602 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
603 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
605 Namespace namespace = lm.get(nsd.value.name);
606 if (namespace==null) {
608 namespace = other.remove(nsd.value.name);
610 if (namespace==null) {
611 namespace = new Namespace(nsd.value);
612 namespace.admin=new ArrayList<>();
613 namespace.owner=new ArrayList<>();
615 if (endsWith==null || urdd.role.endsWith(endsWith)) {
616 lm.put(namespace.name,namespace);
618 other.put(namespace.name,namespace);
621 if (Question.OWNER.equals(urdd.rname)) {
622 namespace.owner.add(urdd.user);
624 namespace.admin.add(urdd.user);
630 return Result.ok(lm.values());
635 path = "/authz/nss/responsible/:id",
636 params = { "id|string|true" },
638 errorCodes = { 403,404 },
639 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
640 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
644 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
645 final Validator v = new ServiceValidator();
646 if (v.nullOrBlank("User", user).err()) {
647 return Result.err(Status.ERR_BadData, v.errs());
649 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
651 return Result.err(rn);
654 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
656 NSS nss = mapper.newInstance(API.NSS);
657 // Note: "loadNamespace" prevalidates
658 return mapper.nss(trans, rn.value, nss);
663 path = "/authz/nss/children/:id",
664 params = { "id|string|true" },
666 errorCodes = { 403,404 },
667 text = { "Lists all Child Namespaces of Namespace :id",
668 "Note: This is not a cached read"
672 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
673 final Validator v = new ServiceValidator();
674 if (v.nullOrBlank("NS", parent).err()) {
675 return Result.err(Status.ERR_BadData,v.errs());
678 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
680 return Result.err(rnd);
682 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
684 return Result.err(rnd);
687 Set<Namespace> lm = new HashSet<>();
688 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().dao().getChildren(trans, parent);
690 if (rlnd.isEmpty()) {
691 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
693 for (NsDAO.Data ndd : rlnd.value) {
694 Namespace namespace = new Namespace(ndd);
695 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
697 namespace.admin=rls.value;
700 rls = func.getOwners(trans, namespace.name, false);
702 namespace.owner=rls.value;
707 NSS nss = mapper.newInstance(API.NSS);
708 return mapper.nss(trans,lm, nss);
710 return Result.err(rlnd);
720 errorCodes = { 403,404,406 },
721 text = { "Replace the Current Description of a Namespace with a new one"
725 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
726 final Result<Namespace> nsd = mapper.ns(trans, from);
727 final ServiceValidator v = new ServiceValidator();
728 if (v.ns(nsd).err()) {
729 return Result.err(Status.ERR_BadData,v.errs());
731 if (v.nullOrBlank("description", nsd.value.description).err()) {
732 return Result.err(Status.ERR_BadData,v.errs());
735 Namespace namespace = nsd.value;
736 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, namespace.name);
738 if (rlnd.notOKorIsEmpty()) {
739 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
742 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
743 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
746 Result<Void> rdr = ques.nsDAO().dao().addDescription(trans, namespace.name, namespace.description);
750 return Result.err(rdr);
756 * @throws DAOException
757 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
761 path = "/authz/ns/:ns",
762 params = { "ns|string|true" },
764 errorCodes = { 403,404,424 },
765 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
766 "are still credentials associated with them, but they can be deleted by setting ",
767 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
768 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
769 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
770 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
771 + "at or below Application Scope"
775 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
776 return func.deleteNS(trans, ns);
780 /***********************************
782 ***********************************/
786 * @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)
790 path = "/authz/perm",
793 errorCodes = {403,404,406,409},
794 text = { "Permission consists of:",
795 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
796 + "is being protected</li>",
797 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
798 + " instance of the type</li>",
799 "<li>action - what kind of action is allowed</li></ul>",
800 "Note: instance and action can be an *"
804 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
805 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
807 final ServiceValidator v = new ServiceValidator();
808 if (v.perm(newPd).err()) {
809 return Result.err(Status.ERR_BadData,v.errs());
812 // User Permission mechanism
813 if(newPd.value.ns.indexOf('@')>0) {
814 PermDAO.Data pdd = newPd.value;
815 if(trans.user().equals(newPd.value.ns)) {
816 CachedPermDAO permDAO = ques.permDAO();
817 Result<List<PermDAO.Data>> rlpdd = permDAO.read(trans, pdd);
819 return Result.err(rlpdd);
821 if(!rlpdd.isEmpty()) {
822 return Result.err(Result.ERR_ConflictAlreadyExists,"Permission already exists");
825 RoleDAO.Data rdd = new RoleDAO.Data();
829 pdd.roles(true).add(rdd.encode());
830 Result<PermDAO.Data> rpdd = permDAO.create(trans, pdd);
832 return Result.err(rpdd);
835 CachedRoleDAO roleDAO = ques.roleDAO();
836 Result<List<RoleDAO.Data>> rlrdd = roleDAO.read(trans, rdd);
838 return Result.err(rlrdd);
840 if(!rlrdd.isEmpty()) {
841 rdd = rlrdd.value.get(0);
845 String eperm = pdd.encode();
846 rdd.perms(true).add(eperm);
847 Result<Void> rv = roleDAO.update(trans, rdd);
852 CachedUserRoleDAO urDAO = ques.userRoleDAO();
853 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
854 urdd.user = trans.user();
856 urdd.rname = rdd.name;
857 urdd.role = rdd.fullName();
858 Result<List<UserRoleDAO.Data>> rlurdd = urDAO.read(trans, urdd);
860 return Result.err(rlrdd);
861 } else if(rlurdd.isEmpty()) {
862 GregorianCalendar gc = trans.org().expiration(null, Expiration.UserInRole);
864 return Result.err(Result.ERR_Policy,"Organzation does not grant Expiration for UserRole");
866 urdd.expires = gc.getTime();
868 Result<UserRoleDAO.Data> rurdd = urDAO.create(trans, urdd);
869 return Result.err(rurdd);
873 return Result.err(Result.ERR_Security,"Only the User can create User Permissions");
876 // Does Perm Type exist as a Namespace?
877 if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
878 return Result.err(Status.ERR_ConflictAlreadyExists,
879 "Permission Type exists as a Namespace");
882 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
885 public String get() {
886 return "Create Permission [" +
887 newPd.value.fullType() + '|' +
888 newPd.value.instance + '|' +
889 newPd.value.action + ']';
893 private Result<NsDAO.Data> nsd;
895 public Result<?> mayChange() {
897 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
903 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
904 if (nsr.notOKorIsEmpty()) {
905 return Result.err(nsr);
909 Result<String> rfc = func.createFuture(trans,fd.value,
910 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
915 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
918 newPd.value.instance,
921 return Result.err(rfc);
924 return func.createPerm(trans, newPd.value, true);
926 return Result.err(fd);
933 path = "/authz/perms/:type",
934 params = {"type|string|true"},
936 errorCodes = { 404,406 },
937 text = { "List All Permissions that match the :type element of the key" }
940 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
941 final Validator v = new ServiceValidator();
942 if (v.nullOrBlank("PermType", permType).err()) {
943 return Result.err(Status.ERR_BadData,v.errs());
946 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
948 return Result.err(rlpd);
951 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
952 // Result<NsDAO.Data> r;
953 // if ((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
955 PERMS perms = mapper.newInstance(API.PERMS);
956 if (!rlpd.isEmpty()) {
957 // Note: Mapper will restrict what can be viewed
958 return mapper.perms(trans, rlpd.value, perms, true);
960 return Result.ok(perms);
965 path = "/authz/perms/:type/:instance/:action",
966 params = {"type|string|true",
967 "instance|string|true",
968 "action|string|true"},
970 errorCodes = { 404,406 },
971 text = { "List Permissions that match key; :type, :instance and :action" }
974 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
975 final Validator v = new ServiceValidator();
976 if (v.nullOrBlank("PermType", type).err()
977 || v.nullOrBlank("PermInstance", instance).err()
978 || v.nullOrBlank("PermAction", action).err()) {
979 return Result.err(Status.ERR_BadData,v.errs());
982 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
984 return Result.err(rlpd);
987 PERMS perms = mapper.newInstance(API.PERMS);
988 if (!rlpd.isEmpty()) {
989 // Note: Mapper will restrict what can be viewed
990 return mapper.perms(trans, rlpd.value, perms, true);
992 return Result.ok(perms);
997 path = "/authz/perms/user/:user",
998 params = {"user|string|true"},
1000 errorCodes = { 404,406 },
1001 text = { "List All Permissions that match user :user",
1002 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
1005 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
1006 final Validator v = new ServiceValidator();
1007 if (v.nullOrBlank("User", user).err()) {
1008 return Result.err(Status.ERR_BadData,v.errs());
1011 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,
1012 trans.requested(force));
1014 return Result.err(rlpd);
1017 PERMS perms = mapper.newInstance(API.PERMS);
1019 if (rlpd.isEmpty()) {
1020 return Result.ok(perms);
1022 // Note: Mapper will restrict what can be viewed
1023 // if user is the same as that which is looked up, no filtering is required
1024 return mapper.perms(trans, rlpd.value,
1026 !user.equals(trans.user()));
1031 path = "/authz/perms/user/:user/scope/:scope",
1032 params = {"user|string|true","scope|string|true"},
1034 errorCodes = { 404,406 },
1035 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
1036 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1037 "<p>'scope' must be expressed as NSs separated by ':'</p>"
1041 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
1042 final Validator v = new ServiceValidator();
1043 if (v.nullOrBlank("User", user).err()) {
1044 return Result.err(Status.ERR_BadData,v.errs());
1047 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
1049 return Result.err(rlpd);
1052 PERMS perms = mapper.newInstance(API.PERMS);
1054 if (rlpd.isEmpty()) {
1055 return Result.ok(perms);
1057 // Note: Mapper will restrict what can be viewed
1058 // if user is the same as that which is looked up, no filtering is required
1059 return mapper.perms(trans, rlpd.value,
1062 !user.equals(trans.user()));
1067 path = "/authz/perms/user/:user",
1068 params = {"user|string|true"},
1070 errorCodes = { 404,406 },
1071 text = { "List All Permissions that match user :user",
1072 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1074 "Present Queries as one or more Permissions (see ContentType Links below for format).",
1076 "If the Caller is Granted this specific Permission, and the Permission is valid",
1077 " for the User, it will be included in response Permissions, along with",
1078 " all the normal permissions on the 'GET' version of this call. If it is not",
1079 " valid, or Caller does not have permission to see, it will be removed from the list",
1081 " *Note: This design allows you to make one call for all expected permissions",
1082 " The permission to be included MUST be:",
1083 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1085 " com.att.myns.access|:ns|write",
1086 " com.att.myns.access|:role:myrole|create",
1087 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1092 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1093 PERMS perms = _perms;
1094 final Validator v = new ServiceValidator();
1095 if (v.nullOrBlank("User", user).err()) {
1096 return Result.err(Status.ERR_BadData,v.errs());
1100 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.requested(force));
1102 return Result.err(rlpd);
1106 1) See if allowed to query
1107 2) See if User is allowed
1109 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1110 if (in.isOKhasData()) {
1111 List<PermDAO.Data> out = rlpd.value;
1113 for (PermDAO.Data pdd : in.value) {
1115 if ("access".equals(pdd.type)) {
1116 Access access = Access.valueOf(pdd.action);
1117 String[] mdkey = Split.splitTrim(':',pdd.instance);
1118 if (mdkey.length>1) {
1119 String type = mdkey[1];
1120 if ("role".equals(type)) {
1121 if (mdkey.length>2) {
1122 RoleDAO.Data rdd = new RoleDAO.Data();
1125 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1127 } else if ("perm".equals(type)) {
1128 if (mdkey.length>4) { // also need instance/action
1129 PermDAO.Data p = new PermDAO.Data();
1132 p.instance=mdkey[3];
1134 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1136 } else if ("ns".equals(type)) {
1137 NsDAO.Data ndd = new NsDAO.Data();
1139 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1149 perms = mapper.newInstance(API.PERMS);
1150 if (rlpd.isEmpty()) {
1151 return Result.ok(perms);
1153 // Note: Mapper will restrict what can be viewed
1154 // if user is the same as that which is looked up, no filtering is required
1155 return mapper.perms(trans, rlpd.value,
1157 !user.equals(trans.user()));
1162 path = "/authz/perms/role/:role",
1163 params = {"role|string|true"},
1165 errorCodes = { 404,406 },
1166 text = { "List All Permissions that are granted to :role" }
1169 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1170 final Validator v = new ServiceValidator();
1171 if (v.nullOrBlank("Role", role).err()) {
1172 return Result.err(Status.ERR_BadData,v.errs());
1175 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1177 return Result.err(rrdd);
1180 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1182 return Result.err(r);
1185 PERMS perms = mapper.newInstance(API.PERMS);
1187 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1188 if (rlpd.isOKhasData()) {
1189 // Note: Mapper will restrict what can be viewed
1190 return mapper.perms(trans, rlpd.value, perms, true);
1192 return Result.ok(perms);
1197 path = "/authz/perms/ns/:ns",
1198 params = {"ns|string|true"},
1200 errorCodes = { 404,406 },
1201 text = { "List All Permissions that are in Namespace :ns" }
1204 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1205 final Validator v = new ServiceValidator();
1206 if (v.nullOrBlank("NS", ns).err()) {
1207 return Result.err(Status.ERR_BadData,v.errs());
1210 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1212 return Result.err(rnd);
1215 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1217 return Result.err(rnd);
1220 Result<List<PermDAO.Data>> rlpd = ques.permDAO().readNS(trans, ns);
1222 return Result.err(rlpd);
1225 PERMS perms = mapper.newInstance(API.PERMS);
1226 if (!rlpd.isEmpty()) {
1227 // Note: Mapper will restrict what can be viewed
1228 return mapper.perms(trans, rlpd.value,perms, true);
1230 return Result.ok(perms);
1235 path = "/authz/perm/:type/:instance/:action",
1236 params = {"type|string|true",
1237 "instance|string|true",
1238 "action|string|true"},
1240 errorCodes = { 404,406, 409 },
1241 text = { "Rename the Permission referenced by :type :instance :action, and "
1242 + "rename (copy/delete) to the Permission described in PermRequest" }
1245 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1246 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1247 final ServiceValidator v = new ServiceValidator();
1248 if (v.perm(newPd).err()) {
1249 return Result.err(Status.ERR_BadData,v.errs());
1252 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1253 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1254 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1257 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1258 Result<List<PermDAO.Data>> origRlpd = ques.permDAO().read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1260 if (origRlpd.notOKorIsEmpty()) {
1261 return Result.err(Status.ERR_PermissionNotFound,
1262 "Permission [%s|%s|%s] does not exist",
1263 origType,origInstance,origAction);
1266 PermDAO.Data origPd = origRlpd.value.get(0);
1268 if (!origPd.ns.equals(newPd.value.ns)) {
1269 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1270 "<new type> must start with [" + origPd.ns + "]");
1273 if ( origPd.type.equals(newPd.value.type) &&
1274 origPd.action.equals(newPd.value.action) &&
1275 origPd.instance.equals(newPd.value.instance) ) {
1276 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1279 Set<String> origRoles = origPd.roles(false);
1280 if (!origRoles.isEmpty()) {
1281 Set<String> roles = newPd.value.roles(true);
1282 for (String role : origPd.roles) {
1287 newPd.value.description = origPd.description;
1289 Result<Void> rv = null;
1291 rv = func.createPerm(trans, newPd.value, false);
1293 rv = func.deletePerm(trans, origPd, true, false);
1300 path = "/authz/perm",
1303 errorCodes = { 404,406 },
1304 text = { "Add Description Data to Perm" }
1307 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1308 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1309 final ServiceValidator v = new ServiceValidator();
1310 if (v.perm(pd).err()) {
1311 return Result.err(Status.ERR_BadData,v.errs());
1313 if (v.nullOrBlank("description", pd.value.description).err()) {
1314 return Result.err(Status.ERR_BadData,v.errs());
1316 final PermDAO.Data perm = pd.value;
1317 if (ques.permDAO().read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1318 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1319 perm.ns,perm.type,perm.instance,perm.action);
1322 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1323 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1324 perm.ns,perm.type,perm.instance,perm.action);
1327 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pd.value.ns);
1328 if (nsr.notOKorIsEmpty()) {
1329 return Result.err(nsr);
1332 Result<Void> rdr = ques.permDAO().addDescription(trans, perm.ns, perm.type, perm.instance,
1333 perm.action, perm.description);
1337 return Result.err(rdr);
1344 path = "/authz/role/perm",
1347 errorCodes = {403,404,406,409},
1348 text = { "Set a permission's roles to roles given" }
1352 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1353 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1354 if (updt.notOKorIsEmpty()) {
1355 return Result.err(updt);
1358 final ServiceValidator v = new ServiceValidator();
1359 if (v.perm(updt).err()) {
1360 return Result.err(Status.ERR_BadData,v.errs());
1363 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1365 return Result.err(nsd);
1368 // Read full set to get CURRENT values
1369 Result<List<PermDAO.Data>> rcurr = ques.permDAO().read(trans,
1372 updt.value.instance,
1375 if (rcurr.notOKorIsEmpty()) {
1376 return Result.err(Status.ERR_PermissionNotFound,
1377 "Permission [%s.%s|%s|%s] does not exist",
1378 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1381 // Create a set of Update Roles, which are in Internal Format
1382 Set<String> updtRoles = new HashSet<>();
1383 Result<NsSplit> nss;
1384 for (String role : updt.value.roles(false)) {
1385 nss = ques.deriveNsSplit(trans, role);
1387 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1389 trans.error().log(nss.errorString());
1393 Result<Void> rv = null;
1395 for (PermDAO.Data curr : rcurr.value) {
1396 Set<String> currRoles = curr.roles(false);
1397 // must add roles to this perm, and add this perm to each role
1398 // in the update, but not in the current
1399 for (String role : updtRoles) {
1400 if (!currRoles.contains(role)) {
1401 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1402 if (key.isOKhasData()) {
1403 Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, key.value);
1404 if (rrd.isOKhasData()) {
1405 for (RoleDAO.Data r : rrd.value) {
1406 rv = func.addPermToRole(trans, r, curr, false);
1407 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1408 return Result.err(rv);
1412 return Result.err(rrd);
1417 // similarly, must delete roles from this perm, and delete this perm from each role
1418 // in the update, but not in the current
1419 for (String role : currRoles) {
1420 if (!updtRoles.contains(role)) {
1421 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1422 if (key.isOKhasData()) {
1423 Result<List<RoleDAO.Data>> rdd = ques.roleDAO().read(trans, key.value);
1424 if (rdd.isOKhasData()) {
1425 for (RoleDAO.Data r : rdd.value) {
1426 rv = func.delPermFromRole(trans, r, curr, true);
1427 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1428 return Result.err(rv);
1436 return rv==null?Result.ok():rv;
1441 path = "/authz/perm",
1444 errorCodes = { 404,406 },
1445 text = { "Delete the Permission referenced by PermKey.",
1446 "You cannot normally delete a permission which is still granted to roles,",
1447 "however the \"force\" property allows you to do just that. To do this: Add",
1448 "'force=true' as a query parameter.",
1449 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1452 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1453 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1455 return Result.err(pd);
1457 final ServiceValidator v = new ServiceValidator();
1458 if (v.nullOrBlank(pd.value).err()) {
1459 return Result.err(Status.ERR_BadData,v.errs());
1461 final PermDAO.Data perm = pd.value;
1462 if (ques.permDAO().read(trans, perm).notOKorIsEmpty()) {
1463 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1464 perm.ns,perm.type,perm.instance,perm.action );
1467 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1470 public String get() {
1471 return "Delete Permission [" + perm.fullPerm() + ']';
1475 private Result<NsDAO.Data> nsd;
1477 public Result<?> mayChange() {
1479 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1487 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, perm.ns);
1488 if (nsr.notOKorIsEmpty()) {
1489 return Result.err(nsr);
1492 Result<String> rfc = func.createFuture(trans, fd.value,
1493 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1495 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1497 return Result.err(rfc);
1499 case Status.ACC_Now:
1500 return func.deletePerm(trans,perm,trans.requested(force), false);
1502 return Result.err(fd);
1508 path = "/authz/perm/:name/:type/:action",
1509 params = {"type|string|true",
1510 "instance|string|true",
1511 "action|string|true"},
1513 errorCodes = { 404,406 },
1514 text = { "Delete the Permission referenced by :type :instance :action",
1515 "You cannot normally delete a permission which is still granted to roles,",
1516 "however the \"force\" property allows you to do just that. To do this: Add",
1517 "'force=true' as a query parameter",
1518 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1521 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1522 final Validator v = new ServiceValidator();
1523 if (v.nullOrBlank("Type",type)
1524 .nullOrBlank("Instance",instance)
1525 .nullOrBlank("Action",action)
1527 return Result.err(Status.ERR_BadData,v.errs());
1530 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1532 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1534 return Result.err(pd);
1538 /***********************************
1540 ***********************************/
1543 path = "/authz/role",
1546 errorCodes = {403,404,406,409},
1549 "Roles are part of Namespaces",
1551 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1552 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1553 "Restrictions on Role Names:",
1554 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1555 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1556 "<li>role names are Case Sensitive</li></ul>",
1557 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1558 "<ul><li>'What Job Function does this represent?'</li>",
1559 "<li>'Does this person perform this Job Function?'</li></ul>" }
1563 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1564 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1565 // Does Perm Type exist as a Namespace?
1566 if(rd.value.name.isEmpty() || ques.nsDAO().read(trans, rd.value.fullName()).isOKhasData()) {
1567 return Result.err(Status.ERR_ConflictAlreadyExists,
1568 "Role exists as a Namespace");
1570 final ServiceValidator v = new ServiceValidator();
1571 if (v.role(rd).err()) {
1572 return Result.err(Status.ERR_BadData,v.errs());
1574 final RoleDAO.Data role = rd.value;
1575 if (ques.roleDAO().read(trans, role.ns, role.name).isOKhasData()) {
1576 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1579 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1582 public String get() {
1583 return "Create Role [" +
1584 rd.value.fullName() +
1589 private Result<NsDAO.Data> nsd;
1591 public Result<?> mayChange() {
1593 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1599 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1600 if (nsr.notOKorIsEmpty()) {
1601 return Result.err(nsr);
1606 Result<String> rfc = func.createFuture(trans, fd.value,
1607 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1609 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1613 return Result.err(rfc);
1615 case Status.ACC_Now:
1616 Result<RoleDAO.Data> rdr = ques.roleDAO().create(trans, role);
1620 return Result.err(rdr);
1623 return Result.err(fd);
1628 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1632 path = "/authz/roles/:role",
1633 params = {"role|string|true"},
1635 errorCodes = {404,406},
1636 text = { "List Roles that match :role",
1637 "Note: You must have permission to see any given role"
1641 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1642 final Validator v = new ServiceValidator();
1643 if (v.nullOrBlank("Role", role).err()) {
1644 return Result.err(Status.ERR_BadData,v.errs());
1647 // Determine if User can ask this question
1648 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1649 if (rrdd.isOKhasData()) {
1650 Result<NsDAO.Data> r;
1651 if ((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1652 return Result.err(r);
1655 return Result.err(rrdd);
1659 int query = role.indexOf('?');
1660 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1662 // Note: Mapper will restrict what can be viewed
1663 ROLES roles = mapper.newInstance(API.ROLES);
1664 return mapper.roles(trans, rlrd.value, roles, true);
1666 return Result.err(rlrd);
1671 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1675 path = "/authz/roles/user/:name",
1676 params = {"name|string|true"},
1678 errorCodes = {404,406},
1679 text = { "List all Roles that match user :name",
1680 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1681 "Note: You must have permission to see any given role"
1686 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1687 final Validator v = new ServiceValidator();
1688 if (v.nullOrBlank("User", user).err()) {
1689 return Result.err(Status.ERR_BadData,v.errs());
1692 ROLES roles = mapper.newInstance(API.ROLES);
1693 // Get list of roles per user, then add to Roles as we go
1694 Result<List<RoleDAO.Data>> rlrd;
1695 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
1696 if (rlurd.isOKhasData()) {
1697 for (UserRoleDAO.Data urd : rlurd.value ) {
1698 rlrd = ques.roleDAO().read(trans, urd.ns,urd.rname);
1699 // Note: Mapper will restrict what can be viewed
1700 // if user is the same as that which is looked up, no filtering is required
1701 if (rlrd.isOKhasData()) {
1702 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1706 return Result.ok(roles);
1711 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1715 path = "/authz/roles/ns/:ns",
1716 params = {"ns|string|true"},
1718 errorCodes = {404,406},
1719 text = { "List all Roles for the Namespace :ns",
1720 "Note: You must have permission to see any given role"
1725 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1726 final Validator v = new ServiceValidator();
1727 if (v.nullOrBlank("NS", ns).err()) {
1728 return Result.err(Status.ERR_BadData,v.errs());
1731 // check if user is allowed to view NS
1732 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1734 return Result.err(rnsd);
1736 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1738 return Result.err(rnsd);
1741 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1743 ROLES roles = mapper.newInstance(API.ROLES);
1744 // Get list of roles per user, then add to Roles as we go
1745 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readNS(trans, ns);
1747 if (!rlrd.isEmpty()) {
1748 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1749 mapper.roles(trans,rlrd.value,roles,false);
1751 return Result.ok(roles);
1753 return Result.err(rlrd);
1762 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1766 path = "/authz/roles/name/:name",
1767 params = {"name|string|true"},
1769 errorCodes = {404,406},
1770 text = { "List all Roles for only the Name of Role (without Namespace)",
1771 "Note: You must have permission to see any given role"
1775 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1776 final Validator v = new ServiceValidator();
1777 if (v.nullOrBlank("Name", name).err()) {
1778 return Result.err(Status.ERR_BadData,v.errs());
1781 // User Mapper to make sure user is allowed to view NS
1783 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1785 ROLES roles = mapper.newInstance(API.ROLES);
1786 // Get list of roles per user, then add to Roles as we go
1787 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readName(trans, name);
1789 if (!rlrd.isEmpty()) {
1790 // Note: Mapper will restrict what can be viewed
1791 mapper.roles(trans,rlrd.value,roles,true);
1793 return Result.ok(roles);
1795 return Result.err(rlrd);
1804 path = "/authz/roles/perm/:type/:instance/:action",
1805 params = {"type|string|true",
1806 "instance|string|true",
1807 "action|string|true"},
1809 errorCodes = {404,406},
1810 text = { "Find all Roles containing the given Permission." +
1811 "Permission consists of:",
1812 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1813 + "is being protected</li>",
1814 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1815 + " instance of the type</li>",
1816 "<li>action - what kind of action is allowed</li></ul>",
1817 "Notes: instance and action can be an *",
1818 " You must have permission to see any given role"
1823 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1824 final Validator v = new ServiceValidator();
1825 if (v.permType(type)
1826 .permInstance(instance)
1829 return Result.err(Status.ERR_BadData,v.errs());
1832 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1834 ROLES roles = mapper.newInstance(API.ROLES);
1835 // Get list of roles per user, then add to Roles as we go
1836 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1837 if (nsSplit.isOK()) {
1838 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1840 if ((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1841 return Result.err(res);
1844 Result<List<PermDAO.Data>> pdlr = ques.permDAO().read(trans, pdd);
1845 if (pdlr.isOK())for (PermDAO.Data pd : pdlr.value) {
1846 Result<List<RoleDAO.Data>> rlrd;
1847 for (String r : pd.roles) {
1848 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1850 rlrd = ques.roleDAO().read(trans, rs.value[0],rs.value[1]);
1851 // Note: Mapper will restrict what can be viewed
1852 if (rlrd.isOKhasData()) {
1853 mapper.roles(trans,rlrd.value,roles,true);
1859 return Result.ok(roles);
1867 path = "/authz/role",
1870 errorCodes = {404,406},
1871 text = { "Add Description Data to a Role" }
1875 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1876 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1877 final ServiceValidator v = new ServiceValidator();
1878 if (v.role(rd).err()) {
1879 return Result.err(Status.ERR_BadData,v.errs());
1881 if (v.nullOrBlank("description", rd.value.description).err()) {
1882 return Result.err(Status.ERR_BadData,v.errs());
1885 final RoleDAO.Data role = rd.value;
1886 if (ques.roleDAO().read(trans, role.ns, role.name).notOKorIsEmpty()) {
1887 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1890 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1891 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1894 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1895 if (nsr.notOKorIsEmpty()) {
1896 return Result.err(nsr);
1899 Result<Void> rdr = ques.roleDAO().addDescription(trans, role.ns, role.name, role.description);
1903 return Result.err(rdr);
1910 path = "/authz/role/perm",
1913 errorCodes = {403,404,406,409},
1914 text = { "Grant a Permission to a Role",
1915 "Permission consists of:",
1916 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1917 + "is being protected</li>",
1918 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1919 + " instance of the type</li>",
1920 "<li>action - what kind of action is allowed</li></ul>",
1921 "Note: instance and action can be an *",
1922 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1923 " ID is allowed to create. It will then grant",
1924 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1929 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1930 // Translate Request into Perm and Role Objects
1931 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1932 if (rpd.notOKorIsEmpty()) {
1933 return Result.err(rpd);
1935 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1936 if (rrd.notOKorIsEmpty()) {
1937 return Result.err(rrd);
1940 // Validate Role and Perm values
1941 final ServiceValidator v = new ServiceValidator();
1942 if (v.perm(rpd.value)
1945 return Result.err(Status.ERR_BadData,v.errs());
1948 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().read(trans, rrd.value.ns, rrd.value.name);
1949 if (rlrd.notOKorIsEmpty()) {
1950 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1953 // Check Status of Data in DB (does it exist)
1954 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, rpd.value.ns,
1955 rpd.value.type, rpd.value.instance, rpd.value.action);
1956 PermDAO.Data createPerm = null; // if not null, create first
1957 if (rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1958 if (trans.requested(force)) {
1959 // Remove roles from perm data object so we just create the perm here
1960 createPerm = rpd.value;
1961 createPerm.roles.clear();
1963 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1964 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1967 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1968 return Result.err(Status.ERR_ConflictAlreadyExists,
1969 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1970 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1971 rrd.value.ns,rrd.value.name
1977 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1980 public String get() {
1981 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1982 " to Role [" + rrd.value.fullName() + "]";
1986 private Result<NsDAO.Data> nsd;
1988 public Result<?> mayChange() {
1990 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1995 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rpd.value.ns);
1996 if (nsr.notOKorIsEmpty()) {
1997 return Result.err(nsr);
2001 Result<String> rfc = func.createFuture(trans,fd.value,
2002 rpd.value.fullPerm(),
2007 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2013 return Result.err(rfc);
2015 case Status.ACC_Now:
2016 Result<Void> rv = null;
2017 if (createPerm!=null) {// has been validated for creating
2018 rv = func.createPerm(trans, createPerm, false);
2020 if (rv==null || rv.isOK()) {
2021 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
2025 return Result.err(fd);
2031 * Delete Perms from Roles (UnGrant)
2033 * @param roleFullName
2038 path = "/authz/role/:role/perm",
2039 params = {"role|string|true"},
2041 errorCodes = {404,406},
2042 text = { "Ungrant a permission from Role :role" }
2046 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
2047 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
2048 if (updt.notOKorIsEmpty()) {
2049 return Result.err(updt);
2051 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
2052 if (rrd.notOKorIsEmpty()) {
2053 return Result.err(rrd);
2056 final ServiceValidator v = new ServiceValidator();
2057 if (v.nullOrBlank(updt.value)
2058 .nullOrBlank(rrd.value)
2060 return Result.err(Status.ERR_BadData,v.errs());
2063 return delPermFromRole(trans, updt.value,rrd.value, rreq);
2066 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
2067 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, pdd.ns, pdd.type,
2068 pdd.instance, pdd.action);
2070 if (rlpd.notOKorIsEmpty()) {
2071 return Result.err(Status.ERR_PermissionNotFound,
2072 "Permission [%s.%s|%s|%s] does not exist",
2073 pdd.ns,pdd.type,pdd.instance,pdd.action);
2076 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
2079 public String get() {
2080 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
2081 " from Role [" + rdd.fullName() + "]";
2085 private Result<NsDAO.Data> nsd;
2087 public Result<?> mayChange() {
2089 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2094 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pdd.ns);
2095 if (nsr.notOKorIsEmpty()) {
2096 return Result.err(nsr);
2100 Result<String> rfc = func.createFuture(trans,fd.value,
2107 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2113 return Result.err(rfc);
2115 case Status.ACC_Now:
2116 return func.delPermFromRole(trans, rdd, pdd, false);
2118 return Result.err(fd);
2125 path = "/authz/role/:role/perm/:type/:instance/:action",
2126 params = {"role|string|true",
2127 "perm type|string|true",
2128 "perm instance|string|true",
2129 "perm action|string|true"
2132 errorCodes = {404,406},
2133 text = { "Ungrant a single permission from Role :role with direct key" }
2137 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2138 Result<Data> rpns = ques.deriveNs(trans, type);
2139 if (rpns.notOKorIsEmpty()) {
2140 return Result.err(rpns);
2143 final Validator v = new ServiceValidator();
2145 .permType(rpns.value.name,rpns.value.parent)
2146 .permInstance(instance)
2149 return Result.err(Status.ERR_BadData,v.errs());
2152 Result<Data> rrns = ques.deriveNs(trans, role);
2153 if (rrns.notOKorIsEmpty()) {
2154 return Result.err(rrns);
2157 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, rrns.value.parent, rrns.value.name);
2158 if (rrd.notOKorIsEmpty()) {
2159 return Result.err(rrd);
2162 final Result<List<PermDAO.Data>> rpd = ques.permDAO().read(trans, rpns.value.parent, rpns.value.name, instance, action);
2163 if (rpd.notOKorIsEmpty()) {
2164 return Result.err(rpd);
2168 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2173 path = "/authz/role/:role",
2174 params = {"role|string|true"},
2176 errorCodes = {404,406},
2177 text = { "Delete the Role named :role"}
2181 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2182 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2183 if (rrdd.isOKhasData()) {
2184 final ServiceValidator v = new ServiceValidator();
2185 if (v.nullOrBlank(rrdd.value).err()) {
2186 return Result.err(Status.ERR_BadData,v.errs());
2188 return func.deleteRole(trans, rrdd.value, false, false);
2190 return Result.err(rrdd);
2196 path = "/authz/role",
2199 errorCodes = { 404,406 },
2200 text = { "Delete the Role referenced by RoleKey",
2201 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2202 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2203 "as a query parameter.",
2204 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2208 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2209 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2210 final ServiceValidator v = new ServiceValidator();
2212 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2214 if (v.nullOrBlank(rd.value).err()) {
2215 return Result.err(Status.ERR_BadData,v.errs());
2217 final RoleDAO.Data role = rd.value;
2218 if (ques.roleDAO().read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2219 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2222 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2223 () -> "Delete Role [" + role.fullName() + ']'
2224 + " and all attached user roles",
2226 private Result<NsDAO.Data> nsd;
2228 public Result<?> mayChange() {
2230 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2238 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
2239 if (nsr.notOKorIsEmpty()) {
2240 return Result.err(nsr);
2243 Result<String> rfc = func.createFuture(trans, fd.value,
2244 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2246 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2250 return Result.err(rfc);
2252 case Status.ACC_Now:
2253 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2255 return Result.err(fd);
2260 /***********************************
2262 ***********************************/
2263 private class MayCreateCred implements MayChange {
2264 private Result<NsDAO.Data> nsd;
2265 private AuthzTrans trans;
2266 private CredDAO.Data cred;
2267 private Executor exec;
2269 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2276 public Result<?> mayChange() {
2278 nsd = ques.validNSOfDomain(trans, cred.id);
2280 // is Ns of CredID valid?
2284 if (trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2287 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2288 if (rmc.isOKhasData()) {
2292 } catch (Exception e) {
2293 trans.warn().log(e);
2296 trans.warn().log(nsd.errorString());
2298 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2302 private class MayChangeCred implements MayChange {
2304 private Result<NsDAO.Data> nsd;
2305 private AuthzTrans trans;
2306 private CredDAO.Data cred;
2307 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
2313 public Result<?> mayChange() {
2314 // User can change himself (but not create)
2316 nsd = ques.validNSOfDomain(trans, cred.id);
2318 // Get the Namespace
2320 String user[] = Split.split('.',trans.user());
2321 if (user.length>2) {
2322 String company = user[user.length-1] + '.' + user[user.length-2];
2323 if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) {
2328 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
2333 private final long DAY_IN_MILLIS = 24*3600*1000L;
2337 path = "/authn/cred",
2340 errorCodes = {403,404,406,409},
2341 text = { "A credential consists of:",
2342 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2343 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2344 "AB1234@myapp.att.com</li>",
2345 "<li>password - Company Policy Compliant Password</li></ul>",
2346 "Note: AAF does support multiple credentials with the same ID.",
2347 "Check with your organization if you have this implemented."
2351 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2352 final String cmdDescription = ("Create User Credential");
2353 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2356 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2357 if (rcred.isOKhasData()) {
2358 rcred = ques.userCredSetup(trans, rcred.value);
2360 final ServiceValidator v = new ServiceValidator();
2362 if (v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2363 return Result.err(Status.ERR_BadData,v.errs());
2367 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2368 Identity mechID = null;
2369 Organization org = trans.org();
2371 mechID = org.getIdentity(trans, rcred.value.id);
2372 } catch (Exception e1) {
2373 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2375 if (mechID==null || !mechID.isFound()) {
2376 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2379 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2380 if (nsr.notOKorIsEmpty()) {
2381 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2385 boolean firstID = false;
2388 CassExecutor exec = new CassExecutor(trans, func);
2389 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2390 if (rlcd.isOKhasData()) {
2391 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2392 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2395 for (CredDAO.Data curr : rlcd.value) {
2396 // May not use the same password in the list
2397 // Note: ASPR specifies character differences, but we don't actually store the
2398 // password to validate char differences.
2400 // byte[] rawCred = rcred.value.type==CredDAO.RAW?null:;
2402 rb = ques.userCredCheck(trans, curr, rcred.value.cred.array());
2404 return Result.err(rb);
2405 } else if (rb.value){
2406 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2407 } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
2408 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
2413 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2414 String theMechID = rcred.value.id;
2415 Boolean otherMechIDs = false;
2416 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2417 for (CredDAO.Data cd : ques.credDAO().readNS(trans,nsr.value.get(0).name).value) {
2418 if (!cd.id.equals(theMechID)) {
2419 otherMechIDs = true;
2424 // We can say "ID does not exist" here
2425 if ((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2426 return Result.err(Status.ERR_Denied, reason);
2429 } catch (Exception e) {
2430 return Result.err(e);
2434 mc = new MayCreateCred(trans, rcred.value, exec);
2436 final CredDAO.Data cdd = rcred.value;
2437 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2440 public String get() {
2441 return cmdDescription + " [" +
2444 + cdd.expires + ']';
2451 Result<String> rfc = func.createFuture(trans, fd.value,
2452 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2453 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2455 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2457 Integer.toString(rcred.value.type),
2458 rcred.value.expires.toString());
2460 return Result.err(rfc);
2462 case Status.ACC_Now:
2465 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
2466 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
2467 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
2468 // Note, we only do this on First time, because of possibility of
2469 // prematurely expiring a production id
2470 if (admins.isOKhasData() && !admins.value.contains(trans.user())) {
2471 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2474 } catch (Exception e) {
2475 trans.error().log(e, "While setting expiration to TempPassword");
2478 Result<?>udr = ques.credDAO().create(trans, rcred.value);
2482 return Result.err(udr);
2484 return Result.err(fd);
2488 return Result.err(rcred);
2497 path = "/authn/creds/ns/:ns",
2498 params = {"ns|string|true"},
2500 errorCodes = {403,404,406},
2501 text = { "Return all IDs in Namespace :ns"
2505 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2506 final Validator v = new ServiceValidator();
2507 if (v.ns(ns).err()) {
2508 return Result.err(Status.ERR_BadData,v.errs());
2511 // check if user is allowed to view NS
2512 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2514 return Result.err(rnd);
2516 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2518 return Result.err(rnd);
2521 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2523 USERS users = mapper.newInstance(API.USERS);
2524 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readNS(trans, ns);
2527 if (!rlcd.isEmpty()) {
2528 return mapper.cred(rlcd.value, users);
2530 return Result.ok(users);
2532 return Result.err(rlcd);
2542 path = "/authn/creds/id/:ns",
2543 params = {"id|string|true"},
2545 errorCodes = {403,404,406},
2546 text = { "Return all IDs in for ID"
2547 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2551 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2552 final Validator v = new ServiceValidator();
2553 if (v.nullOrBlank("ID",id).err()) {
2554 return Result.err(Status.ERR_BadData,v.errs());
2557 String ns = Question.domain2ns(id);
2558 // check if user is allowed to view NS
2559 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2561 return Result.err(rnd);
2563 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2565 return Result.err(rnd);
2568 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2570 USERS users = mapper.newInstance(API.USERS);
2571 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, id);
2574 if (!rlcd.isEmpty()) {
2575 return mapper.cred(rlcd.value, users);
2577 return Result.ok(users);
2579 return Result.err(rlcd);
2589 path = "/authn/certs/id/:id",
2590 params = {"id|string|true"},
2592 errorCodes = {403,404,406},
2593 text = { "Return Cert Info for ID"
2597 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2598 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2600 CERTS certs = mapper.newInstance(API.CERTS);
2601 Result<List<CertDAO.Data>> rlcd = ques.certDAO().readID(trans, id);
2604 if (!rlcd.isEmpty()) {
2605 return mapper.cert(rlcd.value, certs);
2607 return Result.ok(certs);
2609 return Result.err(rlcd);
2619 path = "/authn/cred",
2622 errorCodes = {300,403,404,406},
2623 text = { "Reset a Credential Password. If multiple credentials exist for this",
2624 "ID, you will need to specify which entry you are resetting in the",
2625 "CredRequest object"
2629 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
2630 final String cmdDescription = "Update User Credential";
2631 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2633 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2634 if (rcred.isOKhasData()) {
2635 rcred = ques.userCredSetup(trans, rcred.value);
2637 final ServiceValidator v = new ServiceValidator();
2639 if (v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2640 return Result.err(Status.ERR_BadData,v.errs());
2642 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2643 if (rlcd.notOKorIsEmpty()) {
2644 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2647 MayChange mc = new MayChangeCred(trans, rcred.value);
2648 Result<?> rmc = mc.mayChange();
2650 return Result.err(rmc);
2653 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2655 return Result.err(ri);
2657 int entry = ri.value;
2660 final CredDAO.Data cred = rcred.value;
2662 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2665 public String get() {
2666 return cmdDescription + " [" +
2669 + cred.expires + ']';
2674 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2675 if (nsr.notOKorIsEmpty()) {
2676 return Result.err(nsr);
2681 Result<String> rfc = func.createFuture(trans, fd.value,
2682 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2683 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2685 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2687 Integer.toString(rcred.value.type),
2688 rcred.value.expires.toString());
2690 return Result.err(rfc);
2692 case Status.ACC_Now:
2693 Result<?>udr = null;
2694 // If we are Resetting Password on behalf of someone else (am not the Admin)
2695 // use TempPassword Expiration time.
2697 if (ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2698 exp = Expiration.Password;
2700 exp = Expiration.TempPassword;
2703 Organization org = trans.org();
2704 CredDAO.Data current = rlcd.value.get(entry);
2705 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2706 if (current.expires.equals(rcred.value.expires)
2707 && rlcd.value.get(entry).type==rcred.value.type) {
2708 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2709 gc = Chrono.firstMomentOfDay(gc);
2710 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2711 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2713 rcred.value.expires = org.expiration(null,exp).getTime();
2716 udr = ques.credDAO().create(trans, rcred.value);
2718 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2724 return Result.err(udr);
2726 return Result.err(fd);
2729 return Result.err(rcred);
2737 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
2739 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
2741 if (lcd.size() > 1) {
2742 String inputOption = cr.getEntry();
2743 if (inputOption == null) {
2744 String message = selectCredFromList(lcd, false);
2745 Object[] variables = buildVariables(lcd);
2746 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2748 entry = Integer.parseInt(inputOption) - 1;
2750 if (entry < 0 || entry >= lcd.size()) {
2751 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2754 return Result.ok(entry);
2759 path = "/authn/cred/:days",
2760 params = {"days|string|true"},
2762 errorCodes = {300,403,404,406},
2763 text = { "Extend a Credential Expiration Date. The intention of this API is",
2764 "to avoid an outage in PROD due to a Credential expiring before it",
2765 "can be configured correctly. Measures are being put in place ",
2766 "so that this is not abused."
2770 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2771 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2773 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2774 Organization org = trans.org();
2775 final ServiceValidator v = new ServiceValidator();
2776 if (v.notOK(cred).err() ||
2777 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2778 v.user(org,cred.value.id).err()) {
2779 return Result.err(Status.ERR_BadData,v.errs());
2784 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2785 return Result.err(Status.ERR_Policy,reason);
2787 } catch (Exception e) {
2789 trans.error().log(e, msg="Could not contact Organization for User Validation");
2790 return Result.err(Status.ERR_Denied, msg);
2793 // Get the list of Cred Entries
2794 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2795 if (rlcd.notOKorIsEmpty()) {
2796 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2799 //Need to do the "Pick Entry" mechanism
2800 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2802 return Result.err(ri);
2805 CredDAO.Data found = rlcd.value.get(ri.value);
2806 CredDAO.Data cd = cred.value;
2807 // Copy over the cred
2809 cd.cred = found.cred;
2810 cd.other = found.other;
2811 cd.type = found.type;
2813 cd.notes = "Extended";
2814 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2817 cred = ques.credDAO().create(trans, cd);
2821 return Result.err(cred);
2827 private String[] buildVariables(List<CredDAO.Data> value) {
2828 // ensure credentials are sorted so we can fully automate Cred regression test
2829 Collections.sort(value, (cred1, cred2) -> cred1.expires.compareTo(cred2.expires));
2830 String [] vars = new String[value.size()+1];
2832 for (int i = 0; i < value.size(); i++) {
2833 vars[i+1] = value.get(i).id + " " + value.get(i).type
2834 + " |" + value.get(i).expires;
2839 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
2840 StringBuilder errMessage = new StringBuilder();
2841 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
2842 int numSpaces = value.get(0).id.length() - "Id".length();
2844 errMessage.append(userPrompt + '\n');
2845 errMessage.append(" Id");
2846 for (int i = 0; i < numSpaces; i++) {
2847 errMessage.append(' ');
2849 errMessage.append(" Type Expires" + '\n');
2850 for (int i=0;i<value.size();++i) {
2851 errMessage.append(" %s\n");
2853 errMessage.append("Run same command again with chosen entry as last parameter");
2855 return errMessage.toString();
2861 path = "/authn/cred",
2864 errorCodes = {300,403,404,406},
2865 text = { "Delete a Credential. If multiple credentials exist for this",
2866 "ID, you will need to specify which entry you are deleting in the",
2867 "CredRequest object."
2871 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2872 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2873 final Validator v = new ServiceValidator();
2874 if (v.nullOrBlank("cred", cred.value.id).err()) {
2875 return Result.err(Status.ERR_BadData,v.errs());
2878 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2879 if (rlcd.notOKorIsEmpty()) {
2880 // Empty Creds should have no user_roles.
2881 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2883 for (UserRoleDAO.Data data : rlurd.value) {
2884 ques.userRoleDAO().delete(trans, data, false);
2887 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2889 boolean isLastCred = rlcd.value.size()==1;
2891 MayChange mc = new MayChangeCred(trans,cred.value);
2892 Result<?> rmc = mc.mayChange();
2894 return Result.err(rmc);
2898 if (!trans.requested(force)) {
2899 if (rlcd.value.size() > 1) {
2900 CredRequest cr = (CredRequest)from;
2901 String inputOption = cr.getEntry();
2902 if (inputOption == null) {
2903 String message = selectCredFromList(rlcd.value, true);
2904 Object[] variables = buildVariables(rlcd.value);
2905 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2908 if (inputOption.length()>5) { // should be a date
2909 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2911 for (CredDAO.Data cd : rlcd.value) {
2912 if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2918 entry = Integer.parseInt(inputOption) - 1;
2920 } catch (NullPointerException e) {
2921 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2922 } catch (NumberFormatException e) {
2923 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2926 isLastCred = (entry==-1)?true:false;
2930 if (entry < -1 || entry >= rlcd.value.size()) {
2931 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2935 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2936 () -> "Delete Credential [" +
2941 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
2942 if (nsr.notOKorIsEmpty()) {
2943 return Result.err(nsr);
2948 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2949 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2952 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2954 return Result.err(rfc);
2956 case Status.ACC_Now:
2957 Result<?>udr = null;
2958 if (!trans.requested(force)) {
2959 if (entry<0 || entry >= rlcd.value.size()) {
2960 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
2962 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2964 for (CredDAO.Data curr : rlcd.value) {
2965 udr = ques.credDAO().delete(trans, curr, false);
2967 return Result.err(udr);
2972 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2974 for (UserRoleDAO.Data data : rlurd.value) {
2975 ques.userRoleDAO().delete(trans, data, false);
2980 return Result.err(Result.ERR_NotFound,"No User Data found");
2985 return Result.err(udr);
2987 return Result.err(fd);
2994 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
2995 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
2997 // Note: Mapper assigns RAW type
2998 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
2999 if (data.notOKorIsEmpty()) {
3000 return Result.err(data);
3002 CredDAO.Data cred = data.value; // of the Mapped Cred
3003 if (cred.cred==null) {
3004 return Result.err(Result.ERR_BadData,"No Password");
3006 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
3009 } catch (DAOException e) {
3010 trans.error().log(e,"Error looking up cred");
3011 return Result.err(Status.ERR_Denied,"Credential does not match");
3019 path = "/authn/basicAuth",
3022 errorCodes = { 403 },
3023 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
3024 + "Use /authn/validate instead\n"
3025 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
3026 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
3027 + "security, and 403 if it does not." }
3029 private void basicAuth() {
3030 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
3035 path = "/authn/validate",
3038 errorCodes = { 403 },
3039 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
3040 + "do more than BasicAuth as Credential types exp" }
3043 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
3044 //TODO how to make sure people don't use this in browsers? Do we care?
3045 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
3047 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
3048 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
3049 // Note: Only want to log problem, don't want to send back to end user
3053 trans.audit().log(rq.errorString());
3055 } catch (Exception e) {
3056 trans.warn().log(e);
3060 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
3063 /***********************************
3065 ***********************************/
3068 path = "/authz/userRole",
3071 errorCodes = {403,404,406,409},
3072 text = { "Create a UserRole relationship (add User to Role)",
3073 "A UserRole is an object Representation of membership of a Role for limited time.",
3074 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
3075 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
3076 "before Expirations expire. Namespace owners will be notified by email."
3080 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3081 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3083 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3084 if (urr.notOKorIsEmpty()) {
3085 return Result.err(urr);
3087 final UserRoleDAO.Data userRole = urr.value;
3089 final ServiceValidator v = new ServiceValidator();
3090 if (v.user_role(userRole).err() ||
3091 v.user(trans.org(), userRole.user).err()) {
3092 return Result.err(Status.ERR_BadData,v.errs());
3097 // Check if user can change first
3098 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3099 () -> "Add User [" + userRole.user + "] to Role [" +
3103 private Result<NsDAO.Data> nsd;
3105 public Result<?> mayChange() {
3107 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3108 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3113 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3114 if (nsr.notOKorIsEmpty()) {
3115 return Result.err(nsr);
3120 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3121 userRole.user, nsr.value, FUTURE_OP.C);
3123 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3128 return Result.err(rfc);
3130 case Status.ACC_Now:
3131 return func.addUserRole(trans, userRole);
3133 return Result.err(fd);
3141 * getUserRolesByRole
3145 path = "/authz/userRoles/role/:role",
3146 params = {"role|string|true"},
3148 errorCodes = {404,406},
3149 text = { "List all Users that are attached to Role specified in :role",
3153 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3154 final Validator v = new ServiceValidator();
3155 if (v.nullOrBlank("Role",role).err()) {
3156 return Result.err(Status.ERR_BadData,v.errs());
3159 Result<RoleDAO.Data> rrdd;
3160 rrdd = RoleDAO.Data.decode(trans,ques,role);
3162 return Result.err(rrdd);
3164 // May Requester see result?
3165 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3167 return Result.err(ns);
3170 // boolean filter = true;
3171 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3174 // Get list of roles per user, then add to Roles as we go
3175 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3176 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3178 for (UserRoleDAO.Data data : rlurd.value) {
3183 @SuppressWarnings("unchecked")
3184 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3185 // Checked for permission
3186 mapper.userRoles(trans, userSet, users);
3187 return Result.ok(users);
3190 * getUserRolesByRole
3194 path = "/authz/userRoles/user/:user",
3195 params = {"role|string|true"},
3197 errorCodes = {404,406},
3198 text = { "List all UserRoles for :user",
3202 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3203 final Validator v = new ServiceValidator();
3204 if (v.nullOrBlank("User",user).err()) {
3205 return Result.err(Status.ERR_BadData,v.errs());
3208 // Get list of roles per user, then add to Roles as we go
3209 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
3210 if (rlurd.notOK()) {
3211 return Result.err(rlurd);
3216 * 2) is User's Supervisor
3217 * 3) Has special global access =read permission
3219 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3222 String callingUser = trans.getUserPrincipal().getName();
3223 NsDAO.Data ndd = new NsDAO.Data();
3225 if (user.equals(callingUser)) {
3228 Organization org = trans.org();
3230 Identity orgID = org.getIdentity(trans, user);
3231 Identity manager = orgID==null?null:orgID.responsibleTo();
3232 if (orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3234 } else if (ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3239 } catch (OrganizationException e) {
3245 List<UserRoleDAO.Data> content;
3247 content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos
3249 for (UserRoleDAO.Data data : rlurd.value) {
3251 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3258 content = rlurd.value;
3262 @SuppressWarnings("unchecked")
3263 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3264 // Checked for permission
3265 mapper.userRoles(trans, content, users);
3266 return Result.ok(users);
3274 path = "/authz/userRole/extend/:user/:role",
3275 params = { "user|string|true",
3279 errorCodes = {403,404,406},
3280 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3281 "Requestor must be allowed to modify the role"
3285 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3286 Organization org = trans.org();
3287 final ServiceValidator v = new ServiceValidator();
3288 if (v.user(org, user)
3291 return Result.err(Status.ERR_BadData,v.errs());
3294 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3296 return Result.err(rrdd);
3299 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3300 boolean mayNotChange;
3301 if ((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3302 return Result.err(rcr);
3305 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO().read(trans, user,role);
3307 return Result.err(rr);
3309 for (UserRoleDAO.Data userRole : rr.value) {
3310 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3311 FutureDAO.Data fto = new FutureDAO.Data();
3312 fto.target=UserRoleDAO.TABLE;
3313 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3314 GregorianCalendar now = new GregorianCalendar();
3315 fto.start = now.getTime();
3316 fto.expires = org.expiration(now, Expiration.Future).getTime();
3318 fto.construct = userRole.bytify();
3319 } catch (IOException e) {
3320 trans.error().log(e, "Error while bytifying UserRole for Future");
3321 return Result.err(e);
3324 Result<String> rfc = func.createFuture(trans, fto,
3325 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3327 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3331 return Result.err(rfc);
3334 return func.extendUserRole(trans, userRole, false);
3337 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3342 path = "/authz/userRole/:user/:role",
3343 params = { "user|string|true",
3347 errorCodes = {403,404,406},
3348 text = { "Remove Role :role from User :user."
3352 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3353 Validator val = new ServiceValidator();
3354 if (val.nullOrBlank("User", usr)
3355 .nullOrBlank("Role", role).err()) {
3356 return Result.err(Status.ERR_BadData, val.errs());
3359 boolean mayNotChange;
3360 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3362 return Result.err(rrdd);
3365 RoleDAO.Data rdd = rrdd.value;
3366 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3368 // Make sure we don't delete the last owner of valid NS
3369 if (rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3370 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3373 if (mayNotChange=rns.notOK()) {
3374 if (!trans.requested(future)) {
3375 return Result.err(rns);
3379 Result<List<UserRoleDAO.Data>> rulr;
3380 if ((rulr=ques.userRoleDAO().read(trans, usr, role)).notOKorIsEmpty()) {
3381 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3382 + "Assigned to the Role [ " + role + " ]");
3385 UserRoleDAO.Data userRole = rulr.value.get(0);
3386 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3387 FutureDAO.Data fto = new FutureDAO.Data();
3388 fto.target=UserRoleDAO.TABLE;
3389 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3390 GregorianCalendar now = new GregorianCalendar();
3391 fto.start = now.getTime();
3392 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3394 Result<String> rfc = func.createFuture(trans, fto,
3395 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3397 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3401 return Result.err(rfc);
3404 return ques.userRoleDAO().delete(trans, rulr.value.get(0), false);
3410 path = "/authz/userRole/:user/:role",
3411 params = {"user|string|true",
3412 "role|string|true"},
3414 errorCodes = {403,404,406},
3415 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3419 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3420 final Validator v = new ServiceValidator();
3421 if (v.role(role).nullOrBlank("User", user).err()) {
3422 return Result.err(Status.ERR_BadData,v.errs());
3425 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3426 // if (ns.notOK()) return Result.err(ns);
3428 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3429 // May calling user see by virtue of the Role
3430 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3432 return Result.err(rrdd);
3434 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3436 return Result.err(rnd);
3439 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3440 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readUserInRole(trans, user, role);
3442 for (UserRoleDAO.Data data : rlurd.value) {
3447 @SuppressWarnings("unchecked")
3448 USERS users = (USERS) mapper.newInstance(API.USERS);
3449 mapper.users(trans, userSet, users);
3450 return Result.ok(users);
3455 path = "/authz/users/role/:role",
3456 params = {"user|string|true",
3457 "role|string|true"},
3459 errorCodes = {403,404,406},
3460 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3464 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3465 final Validator v = new ServiceValidator();
3466 if (v.nullOrBlank("Role",role).err()) {
3467 return Result.err(Status.ERR_BadData,v.errs());
3470 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3471 // if (ns.notOK()) return Result.err(ns);
3473 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3474 // May calling user see by virtue of the Role
3475 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3477 return Result.err(rrdd);
3480 boolean contactOnly = false;
3481 // Allow the request of any valid user to find the contact of the NS (Owner)
3482 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3484 if (Question.OWNER.equals(rrdd.value.name)) {
3487 return Result.err(rnd);
3491 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3492 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3494 for (UserRoleDAO.Data data : rlurd.value) {
3495 if (contactOnly) { //scrub data
3496 // Can't change actual object, or will mess up the cache.
3497 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3499 scrub.rname = data.rname;
3500 scrub.role = data.role;
3501 scrub.user = data.user;
3509 @SuppressWarnings("unchecked")
3510 USERS users = (USERS) mapper.newInstance(API.USERS);
3511 mapper.users(trans, userSet, users);
3512 return Result.ok(users);
3516 * getUsersByPermission
3520 path = "/authz/users/perm/:type/:instance/:action",
3521 params = { "type|string|true",
3522 "instance|string|true",
3523 "action|string|true"
3526 errorCodes = {404,406},
3527 text = { "List all Users that have Permission specified by :type :instance :action",
3531 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3532 final Validator v = new ServiceValidator();
3533 if (v.nullOrBlank("Type",type)
3534 .nullOrBlank("Instance",instance)
3535 .nullOrBlank("Action",action)
3537 return Result.err(Status.ERR_BadData,v.errs());
3540 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3542 return Result.err(nss);
3545 Result<List<NsDAO.Data>> nsd = ques.nsDAO().read(trans, nss.value.ns);
3547 return Result.err(nsd);
3550 boolean allInstance = ASTERIX.equals(instance);
3551 boolean allAction = ASTERIX.equals(action);
3552 // Get list of roles per Permission,
3553 // Then loop through Roles to get Users
3554 // Note: Use Sets to avoid processing or responding with Duplicates
3555 Set<String> roleUsed = new HashSet<>();
3556 Set<UserRoleDAO.Data> userSet = new HashSet<>();
3558 if (!nss.isEmpty()) {
3559 Result<List<PermDAO.Data>> rlp = ques.permDAO().readByType(trans, nss.value.ns, nss.value.name);
3560 if (rlp.isOKhasData()) {
3561 for (PermDAO.Data pd : rlp.value) {
3562 if ((allInstance || pd.instance.equals(instance)) &&
3563 (allAction || pd.action.equals(action))) {
3564 if (ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3565 for (String role : pd.roles) {
3566 if (!roleUsed.contains(role)) { // avoid evaluating Role many times
3568 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role.replace('|', '.'));
3569 if (rlurd.isOKhasData()) {
3570 for (UserRoleDAO.Data urd : rlurd.value) {
3581 @SuppressWarnings("unchecked")
3582 USERS users = (USERS) mapper.newInstance(API.USERS);
3583 mapper.users(trans, userSet, users);
3584 return Result.ok(users);
3587 /***********************************
3589 ***********************************/
3591 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3592 final Validator v = new ServiceValidator();
3593 if (v.nullOrBlank("User",user).err()) {
3594 return Result.err(Status.ERR_BadData,v.errs());
3597 Result<NsDAO.Data> rnd;
3598 // Users may look at their own data
3599 if (trans.user().equals(user)) {
3600 // Users may look at their own data
3602 int at = user.indexOf('@');
3603 if (at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3604 NsDAO.Data nsd = new NsDAO.Data();
3605 nsd.name = Question.domain2ns(user);
3606 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3608 return Result.err(rnd);
3611 rnd = ques.validNSOfDomain(trans, user);
3613 return Result.err(rnd);
3616 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3618 return Result.err(rnd);
3622 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readByUser(trans, user, yyyymm);
3624 return Result.err(resp);
3626 return mapper.history(trans, resp.value,sort);
3630 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3631 final Validator v = new ServiceValidator();
3632 if (v.nullOrBlank("Role",role).err()) {
3633 return Result.err(Status.ERR_BadData,v.errs());
3636 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3638 return Result.err(rrdd);
3641 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3643 return Result.err(rnd);
3645 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, role, "role", yyyymm);
3647 return Result.err(resp);
3649 return mapper.history(trans, resp.value,sort);
3653 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3654 final Validator v = new ServiceValidator();
3655 if (v.nullOrBlank("Type",type)
3657 return Result.err(Status.ERR_BadData,v.errs());
3660 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3661 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3663 return Result.err(rnd);
3666 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3668 return Result.err(rnd);
3670 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3672 return Result.err(resp);
3674 return mapper.history(trans, resp.value,sort);
3678 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3679 final Validator v = new ServiceValidator();
3680 if (v.nullOrBlank("NS",ns).err()) {
3681 return Result.err(Status.ERR_BadData,v.errs());
3684 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3686 return Result.err(rnd);
3688 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3690 return Result.err(rnd);
3693 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, ns, "ns", yyyymm);
3695 return Result.err(resp);
3697 return mapper.history(trans, resp.value,sort);
3701 public Result<HISTORY> getHistoryBySubject(AuthzTrans trans, String subject, String target, int[] yyyymm, final int sort) {
3702 NsDAO.Data ndd = new NsDAO.Data();
3703 ndd.name = FQI.reverseDomain(subject);
3704 Result<Data> rnd = ques.mayUser(trans, trans.user(), ndd, Access.read);
3706 return Result.err(rnd);
3709 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, subject, target, yyyymm);
3711 return Result.err(resp);
3713 return mapper.history(trans, resp.value,sort);
3716 /***********************************
3718 ***********************************/
3720 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3721 return createOrUpdateDelegate(trans, base, Question.Access.create);
3725 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3726 return createOrUpdateDelegate(trans, base, Question.Access.write);
3730 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3731 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3732 final ServiceValidator v = new ServiceValidator();
3733 if (v.delegate(trans.org(),rd).err()) {
3734 return Result.err(Status.ERR_BadData,v.errs());
3737 final DelegateDAO.Data dd = rd.value;
3739 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO().read(trans, dd);
3740 if (access==Access.create && ddr.isOKhasData()) {
3741 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3742 } else if (access!=Access.create && ddr.notOKorIsEmpty()) {
3743 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3745 Result<Void> rv = ques.mayUser(trans, dd, access);
3750 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3752 StringBuilder sb = new StringBuilder();
3753 sb.append(access.name());
3754 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3755 sb.append("Delegate ");
3756 sb.append(access==Access.create?"[":"to [");
3757 sb.append(rd.value.delegate);
3758 sb.append("] for [");
3759 sb.append(rd.value.user);
3761 return sb.toString();
3764 return Result.ok(); // Validate in code above
3769 Result<String> rfc = func.createFuture(trans, fd.value,
3770 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3772 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3775 return Result.err(rfc);
3777 case Status.ACC_Now:
3778 if (access==Access.create) {
3779 Result<DelegateDAO.Data> rdr = ques.delegateDAO().create(trans, dd);
3783 return Result.err(rdr);
3786 return ques.delegateDAO().update(trans, dd);
3789 return Result.err(fd);
3794 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3795 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3796 final Validator v = new ServiceValidator();
3797 if (v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3798 return Result.err(Status.ERR_BadData,v.errs());
3801 Result<List<DelegateDAO.Data>> ddl;
3802 if ((ddl=ques.delegateDAO().read(trans, rd.value)).notOKorIsEmpty()) {
3803 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3805 final DelegateDAO.Data dd = ddl.value.get(0);
3806 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3811 return ques.delegateDAO().delete(trans, dd, false);
3815 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3816 DelegateDAO.Data dd = new DelegateDAO.Data();
3817 final Validator v = new ServiceValidator();
3818 if (v.nullOrBlank("User", userName).err()) {
3819 return Result.err(Status.ERR_BadData,v.errs());
3822 Result<List<DelegateDAO.Data>> ddl;
3823 if ((ddl=ques.delegateDAO().read(trans, dd)).notOKorIsEmpty()) {
3824 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3826 dd = ddl.value.get(0);
3827 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3832 return ques.delegateDAO().delete(trans, dd, false);
3836 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
3837 final Validator v = new ServiceValidator();
3838 if (v.nullOrBlank("User", user).err()) {
3839 return Result.err(Status.ERR_BadData,v.errs());
3842 DelegateDAO.Data ddd = new DelegateDAO.Data();
3844 ddd.delegate = null;
3845 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3847 return Result.err(rv);
3850 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
3852 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().read(trans, user);
3854 if (dbDelgs.isOKhasData()) {
3855 return mapper.delegate(dbDelgs.value);
3857 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
3865 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
3866 final Validator v = new ServiceValidator();
3867 if (v.nullOrBlank("Delegate", delegate).err()) {
3868 return Result.err(Status.ERR_BadData,v.errs());
3871 DelegateDAO.Data ddd = new DelegateDAO.Data();
3872 ddd.user = delegate;
3873 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3875 return Result.err(rv);
3878 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
3880 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().readByDelegate(trans, delegate);
3882 if (dbDelgs.isOKhasData()) {
3883 return mapper.delegate(dbDelgs.value);
3885 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
3892 /***********************************
3894 ***********************************/
3895 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
3897 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
3898 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
3900 return Result.err(rlad);
3902 int numApprs = rlad.value.size();
3904 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
3906 int numProcessed = 0;
3907 String user = trans.user();
3909 Result<List<ApprovalDAO.Data>> curr;
3910 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
3911 for (ApprovalDAO.Data updt : rlad.value) {
3912 if (updt.ticket!=null) {
3913 curr = ques.approvalDAO().readByTicket(trans, updt.ticket);
3914 if (curr.isOKhasData()) {
3915 final List<ApprovalDAO.Data> add = curr.value;
3916 // Store a Pre-Lookup
3917 apprByTicket = (trans1, noop) -> add;
3919 } else if (updt.id!=null) {
3920 curr = ques.approvalDAO().read(trans, updt);
3921 } else if (updt.approver!=null) {
3922 curr = ques.approvalDAO().readByApprover(trans, updt.approver);
3924 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
3927 if (curr.isOKhasData()) {
3928 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<>();
3929 Map<UUID, FutureDAO.Data> futureCache = new HashMap<>();
3930 FutureDAO.Data hasDeleted = new FutureDAO.Data();
3932 for (ApprovalDAO.Data cd : curr.value) {
3933 if ("pending".equals(cd.status)) {
3934 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
3936 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
3937 String delegator = cd.approver;
3938 if (updt.id!=null ||
3939 (updt.ticket!=null && user.equals(cd.approver)) ||
3940 (updt.ticket!=null && delegatedAction)) {
3941 if (updt.ticket.equals(cd.ticket)) {
3942 Changed ch = new Changed();
3943 cd.id = ch.changed(cd.id,updt.id);
3944 // cd.ticket = changed(cd.ticket,updt.ticket);
3945 cd.user = ch.changed(cd.user,updt.user);
3946 cd.approver = ch.changed(cd.approver,updt.approver);
3947 cd.type = ch.changed(cd.type,updt.type);
3948 cd.status = ch.changed(cd.status,updt.status);
3949 cd.memo = ch.changed(cd.memo,updt.memo);
3950 cd.operation = ch.changed(cd.operation,updt.operation);
3951 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
3952 // if (updt.status.equals("denied")) {
3953 // cd.last_notified = null;
3955 if (cd.ticket!=null) {
3956 FutureDAO.Data fdd = futureCache.get(cd.ticket);
3957 if (fdd==null) { // haven't processed ticket yet
3958 Result<FutureDAO.Data> rfdd = ques.futureDAO().readPrimKey(trans, cd.ticket);
3960 fdd = rfdd.value; // null is ok
3964 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
3966 if (fdd==hasDeleted) { // YES, by Object
3968 cd.status = "ticketDeleted";
3969 ch.hasChanged(true);
3971 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
3973 trans.info().printf("Approval Status %s is not actionable",cd.status);
3974 } else if (apprByTicket!=null) {
3975 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
3979 if (delegatedAction) {
3980 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
3982 futureCache.put(cd.ticket, hasDeleted);
3986 ch.hasChanged(true);
3987 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
3988 futureCache.put(cd.ticket, hasDeleted);
3993 trans.info().log(rv.toString());
4000 if (ch.hasChanged()) {
4001 ques.approvalDAO().update(trans, cd, true);
4010 if (numApprs==numProcessed) {
4013 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
4017 private static class Changed {
4018 private boolean hasChanged = false;
4020 public<T> T changed(T src, T proposed) {
4021 if (proposed==null || (src!=null && src.equals(proposed))) {
4028 public void hasChanged(boolean b) {
4032 public boolean hasChanged() {
4038 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
4039 final Validator v = new ServiceValidator();
4040 if (v.nullOrBlank("User", user).err()) {
4041 return Result.err(Status.ERR_BadData,v.errs());
4044 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByUser(trans, user);
4046 return mapper.approvals(rapd.value);
4048 return Result.err(rapd);
4053 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
4054 final Validator v = new ServiceValidator();
4055 if (v.nullOrBlank("Ticket", ticket).err()) {
4056 return Result.err(Status.ERR_BadData,v.errs());
4060 uuid = UUID.fromString(ticket);
4061 } catch (IllegalArgumentException e) {
4062 return Result.err(Status.ERR_BadData,e.getMessage());
4065 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByTicket(trans, uuid);
4067 return mapper.approvals(rapd.value);
4069 return Result.err(rapd);
4074 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
4075 final Validator v = new ServiceValidator();
4076 if (v.nullOrBlank("Approver", approver).err()) {
4077 return Result.err(Status.ERR_BadData,v.errs());
4080 List<ApprovalDAO.Data> listRapds = new ArrayList<>();
4082 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO().readByApprover(trans, approver);
4083 if (myRapd.notOK()) {
4084 return Result.err(myRapd);
4087 listRapds.addAll(myRapd.value);
4089 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO().readByDelegate(trans, approver);
4090 if (delegatedFor.isOK()) {
4091 for (DelegateDAO.Data dd : delegatedFor.value) {
4092 if (dd.expires.after(new Date())) {
4093 String delegator = dd.user;
4094 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByApprover(trans, delegator);
4096 for (ApprovalDAO.Data d : rapd.value) {
4097 if (!d.user.equals(trans.user())) {
4106 return mapper.approvals(listRapds);
4110 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4113 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4114 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4115 return ques.clearCache(trans,cname);
4117 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4118 trans.user(),ROOT_NS,CACHE,cname);
4122 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4125 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4126 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4127 Result<Void> v=null;
4128 for (int i: segment) {
4129 v=ques.cacheClear(trans,cname,i);
4135 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4136 trans.user(),ROOT_NS,CACHE,cname);
4140 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4143 public void dbReset(AuthzTrans trans) {
4144 ques.historyDAO().reportPerhapsReset(trans, null);