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.misc.env.Env;
90 import org.onap.aaf.misc.env.TimeTaken;
91 import org.onap.aaf.misc.env.util.Chrono;
92 import org.onap.aaf.misc.env.util.Split;
94 import aaf.v2_0.CredRequest;
97 * AuthzCassServiceImpl implements AuthzCassService for
112 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
113 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
115 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
117 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
119 private static final String ASTERIX = "*";
120 private static final String CACHE = "cache";
121 private static final String ROOT_NS = Define.ROOT_NS();
122 private static final String ROOT_COMPANY = Define.ROOT_COMPANY();
124 private final Question ques;
125 private final Function func;
127 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
128 this.ques = question;
129 func = new Function(trans, question);
130 this.mapper = mapper;
134 /***********************************
136 ***********************************/
139 * @throws DAOException
140 * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
147 errorCodes = { 403,404,406,409 },
148 text = { "Namespace consists of: ",
149 "<ul><li>name - What you want to call this Namespace</li>",
150 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
151 "regarding this Namespace. Companies have Policies as to who may take on ",
152 "this Responsibility. Separate multiple identities with commas</li>",
153 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
154 "including creating Roles, Permissions and Credentials. Separate multiple ",
155 "identities with commas</li></ul>",
156 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
157 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
158 "be an admin of com.myCompany or com"
162 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
163 final Result<Namespace> rnamespace = mapper.ns(trans, from);
164 final ServiceValidator v = new ServiceValidator();
165 if (v.ns(rnamespace).err()) {
166 return Result.err(Status.ERR_BadData,v.errs());
168 final Namespace namespace = rnamespace.value;
169 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
170 if (parentNs.notOK()) {
171 return Result.err(parentNs);
174 // Note: Data validate occurs in func.createNS
175 if (namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
176 return func.createNS(trans, namespace, false);
179 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
182 public String get() {
183 return "Create Namespace [" + namespace.name + ']';
187 private Result<NsDAO.Data> rnd;
189 public Result<?> mayChange() {
191 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
198 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
200 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
202 return Result.err(rfc);
205 return func.createNS(trans, namespace, false);
207 return Result.err(fd);
213 path = "/authz/ns/:ns/admin/:id",
214 params = { "ns|string|true",
218 errorCodes = { 403,404,406,409 },
219 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
220 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
223 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
224 return func.addUserRole(trans, id, ns,Question.ADMIN);
229 path = "/authz/ns/:ns/admin/:id",
230 params = { "ns|string|true",
234 errorCodes = { 403,404 },
235 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
236 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
239 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
240 return func.delAdmin(trans,ns,id);
245 path = "/authz/ns/:ns/responsible/:id",
246 params = { "ns|string|true",
250 errorCodes = { 403,404,406,409 },
251 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
252 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
255 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
256 return func.addUserRole(trans,id,ns,Question.OWNER);
261 path = "/authz/ns/:ns/responsible/:id",
262 params = { "ns|string|true",
266 errorCodes = { 403,404 },
267 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
268 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
269 "Note: A namespace must have at least 1 responsible party"
273 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
274 return func.delOwner(trans,ns,id);
278 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
282 path = "/authz/ns/:ns/attrib/:key/:value",
283 params = { "ns|string|true",
285 "value|string|true"},
287 errorCodes = { 403,404,406,409 },
289 "Create an attribute in the Namespace",
290 "You must be given direct permission for key by AAF"
294 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
295 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
298 final Validator v = new ServiceValidator();
299 if (v.ns(ns).err() ||
301 v.value(value).err()) {
302 return Result.err(Status.ERR_BadData,v.errs());
305 // Check if exists already
306 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
307 if (rlnsd.notOKorIsEmpty()) {
308 return Result.err(rlnsd);
310 NsDAO.Data nsd = rlnsd.value.get(0);
312 // Check for Existence
313 if (nsd.attrib.get(key)!=null) {
314 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
317 // Check if User may put
318 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
319 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
320 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
324 nsd.attrib.put(key, value);
325 ques.nsDAO().dao().attribAdd(trans,ns,key,value);
326 ques.nsDAO().invalidate(trans, nsd);
335 path = "/authz/ns/attrib/:key",
336 params = { "key|string|true" },
338 errorCodes = { 403,404 },
340 "Read Attributes for Namespace"
344 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
346 final Validator v = new ServiceValidator();
347 if (v.nullOrBlank("Key",key).err()) {
348 return Result.err(Status.ERR_BadData,v.errs());
352 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
353 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
354 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
357 Result<Set<String>> rsd = ques.nsDAO().dao().readNsByAttrib(trans, key);
359 return Result.err(rsd);
361 return mapper().keys(rsd.value);
367 path = "/authz/ns/:ns/attrib/:key/:value",
368 params = { "ns|string|true",
371 errorCodes = { 403,404 },
373 "Update Value on an existing attribute in the Namespace",
374 "You must be given direct permission for key by AAF"
378 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
379 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
382 final Validator v = new ServiceValidator();
383 if (v.ns(ns).err() ||
385 v.value(value).err()) {
386 return Result.err(Status.ERR_BadData,v.errs());
389 // Check if exists already (NS must exist)
390 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
391 if (rlnsd.notOKorIsEmpty()) {
392 return Result.err(rlnsd);
394 NsDAO.Data nsd = rlnsd.value.get(0);
396 // Check for Existence
397 if (nsd.attrib.get(key)==null) {
398 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
401 // Check if User may put
402 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
403 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
404 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
408 nsd.attrib.put(key, value);
409 ques.nsDAO().invalidate(trans, nsd);
410 return ques.nsDAO().update(trans,nsd);
419 path = "/authz/ns/:ns/attrib/:key",
420 params = { "ns|string|true",
423 errorCodes = { 403,404 },
425 "Delete an attribute in the Namespace",
426 "You must be given direct permission for key by AAF"
430 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
431 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
434 final Validator v = new ServiceValidator();
435 if (v.nullOrBlank("NS",ns).err() ||
436 v.nullOrBlank("Key",key).err()) {
437 return Result.err(Status.ERR_BadData,v.errs());
440 // Check if exists already
441 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
442 if (rlnsd.notOKorIsEmpty()) {
443 return Result.err(rlnsd);
445 NsDAO.Data nsd = rlnsd.value.get(0);
447 // Check for Existence
448 if (nsd.attrib.get(key)==null) {
449 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
452 // Check if User may del
453 if (!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
454 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
458 nsd.attrib.remove(key);
459 ques.nsDAO().dao().attribRemove(trans,ns,key);
460 ques.nsDAO().invalidate(trans, nsd);
469 path = "/authz/nss/:id",
470 params = { "id|string|true" },
472 errorCodes = { 404,406 },
474 "Lists the Owner(s), Admin(s), Description, and Attributes of Namespace :id",
478 public Result<NSS> getNSbyName(AuthzTrans trans, String ns, boolean includeExpired) {
479 final Validator v = new ServiceValidator();
480 if (v.nullOrBlank("NS", ns).err()) {
481 return Result.err(Status.ERR_BadData,v.errs());
484 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, ns);
486 if (rlnd.isEmpty()) {
487 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
489 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
491 return Result.err(rnd);
495 Namespace namespace = new Namespace(rnd.value);
496 Result<List<String>> rd = func.getOwners(trans, namespace.name, includeExpired);
498 namespace.owner = rd.value;
500 rd = func.getAdmins(trans, namespace.name, includeExpired);
502 namespace.admin = rd.value;
505 NSS nss = mapper.newInstance(API.NSS);
506 return mapper.nss(trans, namespace, nss);
508 return Result.err(rlnd);
514 path = "/authz/nss/admin/:id",
515 params = { "id|string|true" },
517 errorCodes = { 403,404 },
518 text = { "Lists all Namespaces where Identity :id is an Admin",
519 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
523 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
524 final Validator v = new ServiceValidator();
525 if (v.nullOrBlank("User", user).err()) {
526 return Result.err(Status.ERR_BadData, v.errs());
529 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
531 return Result.err(rn);
534 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
536 NSS nss = mapper.newInstance(API.NSS);
537 // Note: "loadNamespace" already validates view of Namespace
538 return mapper.nss(trans, rn.value, nss);
543 path = "/authz/nss/either/:id",
544 params = { "id|string|true" },
546 errorCodes = { 403,404 },
547 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
548 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
552 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
553 final Validator v = new ServiceValidator();
554 if (v.nullOrBlank("User", user).err()) {
555 return Result.err(Status.ERR_BadData, v.errs());
558 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
560 return Result.err(rn);
563 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
565 NSS nss = mapper.newInstance(API.NSS);
566 // Note: "loadNamespace" already validates view of Namespace
567 return mapper.nss(trans, rn.value, nss);
570 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
571 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO().readByUser(trans, user);
572 if (urd.notOKorIsEmpty()) {
573 return Result.err(urd);
575 Map<String, Namespace> lm = new HashMap<>();
576 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<>();
577 for (UserRoleDAO.Data urdd : urd.value) {
579 if (endsWith==null || urdd.role.endsWith(endsWith)) {
580 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
581 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
583 Namespace namespace = lm.get(nsd.value.name);
584 if (namespace==null) {
585 namespace = new Namespace(nsd.value);
586 lm.put(namespace.name,namespace);
588 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
590 namespace.admin=rls.value;
593 rls = func.getOwners(trans, namespace.name, false);
595 namespace.owner=rls.value;
599 } else { // Shortened version. Only Namespace Info available from Role.
600 if (Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
601 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
602 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
604 Namespace namespace = lm.get(nsd.value.name);
605 if (namespace==null) {
607 namespace = other.remove(nsd.value.name);
609 if (namespace==null) {
610 namespace = new Namespace(nsd.value);
611 namespace.admin=new ArrayList<>();
612 namespace.owner=new ArrayList<>();
614 if (endsWith==null || urdd.role.endsWith(endsWith)) {
615 lm.put(namespace.name,namespace);
617 other.put(namespace.name,namespace);
620 if (Question.OWNER.equals(urdd.rname)) {
621 namespace.owner.add(urdd.user);
623 namespace.admin.add(urdd.user);
629 return Result.ok(lm.values());
634 path = "/authz/nss/responsible/:id",
635 params = { "id|string|true" },
637 errorCodes = { 403,404 },
638 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
639 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
643 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
644 final Validator v = new ServiceValidator();
645 if (v.nullOrBlank("User", user).err()) {
646 return Result.err(Status.ERR_BadData, v.errs());
648 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
650 return Result.err(rn);
653 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
655 NSS nss = mapper.newInstance(API.NSS);
656 // Note: "loadNamespace" prevalidates
657 return mapper.nss(trans, rn.value, nss);
662 path = "/authz/nss/children/:id",
663 params = { "id|string|true" },
665 errorCodes = { 403,404 },
666 text = { "Lists all Child Namespaces of Namespace :id",
667 "Note: This is not a cached read"
671 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
672 final Validator v = new ServiceValidator();
673 if (v.nullOrBlank("NS", parent).err()) {
674 return Result.err(Status.ERR_BadData,v.errs());
677 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
679 return Result.err(rnd);
681 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
683 return Result.err(rnd);
686 Set<Namespace> lm = new HashSet<>();
687 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().dao().getChildren(trans, parent);
689 if (rlnd.isEmpty()) {
690 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
692 for (NsDAO.Data ndd : rlnd.value) {
693 Namespace namespace = new Namespace(ndd);
694 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
696 namespace.admin=rls.value;
699 rls = func.getOwners(trans, namespace.name, false);
701 namespace.owner=rls.value;
706 NSS nss = mapper.newInstance(API.NSS);
707 return mapper.nss(trans,lm, nss);
709 return Result.err(rlnd);
719 errorCodes = { 403,404,406 },
720 text = { "Replace the Current Description of a Namespace with a new one"
724 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
725 final Result<Namespace> nsd = mapper.ns(trans, from);
726 final ServiceValidator v = new ServiceValidator();
727 if (v.ns(nsd).err()) {
728 return Result.err(Status.ERR_BadData,v.errs());
730 if (v.nullOrBlank("description", nsd.value.description).err()) {
731 return Result.err(Status.ERR_BadData,v.errs());
734 Namespace namespace = nsd.value;
735 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, namespace.name);
737 if (rlnd.notOKorIsEmpty()) {
738 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
741 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
742 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
745 Result<Void> rdr = ques.nsDAO().dao().addDescription(trans, namespace.name, namespace.description);
749 return Result.err(rdr);
755 * @throws DAOException
756 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
760 path = "/authz/ns/:ns",
761 params = { "ns|string|true" },
763 errorCodes = { 403,404,424 },
764 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
765 "are still credentials associated with them, but they can be deleted by setting ",
766 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
767 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
768 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
769 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
770 + "at or below Application Scope"
774 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
775 return func.deleteNS(trans, ns);
779 /***********************************
781 ***********************************/
785 * @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)
789 path = "/authz/perm",
792 errorCodes = {403,404,406,409},
793 text = { "Permission consists of:",
794 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
795 + "is being protected</li>",
796 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
797 + " instance of the type</li>",
798 "<li>action - what kind of action is allowed</li></ul>",
799 "Note: instance and action can be an *"
803 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
804 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
806 final ServiceValidator v = new ServiceValidator();
807 if (v.perm(newPd).err()) {
808 return Result.err(Status.ERR_BadData,v.errs());
811 // User Permission mechanism
812 if(newPd.value.ns.indexOf('@')>0) {
813 PermDAO.Data pdd = newPd.value;
814 if(trans.user().equals(newPd.value.ns)) {
815 CachedPermDAO permDAO = ques.permDAO();
816 Result<List<PermDAO.Data>> rlpdd = permDAO.read(trans, pdd);
818 return Result.err(rlpdd);
820 if(!rlpdd.isEmpty()) {
821 return Result.err(Result.ERR_ConflictAlreadyExists,"Permission already exists");
824 RoleDAO.Data rdd = new RoleDAO.Data();
828 pdd.roles(true).add(rdd.encode());
829 Result<PermDAO.Data> rpdd = permDAO.create(trans, pdd);
831 return Result.err(rpdd);
834 CachedRoleDAO roleDAO = ques.roleDAO();
835 Result<List<RoleDAO.Data>> rlrdd = roleDAO.read(trans, rdd);
837 return Result.err(rlrdd);
839 if(!rlrdd.isEmpty()) {
840 rdd = rlrdd.value.get(0);
844 String eperm = pdd.encode();
845 rdd.perms(true).add(eperm);
846 Result<Void> rv = roleDAO.update(trans, rdd);
851 CachedUserRoleDAO urDAO = ques.userRoleDAO();
852 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
853 urdd.user = trans.user();
855 urdd.rname = rdd.name;
856 urdd.role = rdd.fullName();
857 Result<List<UserRoleDAO.Data>> rlurdd = urDAO.read(trans, urdd);
859 return Result.err(rlrdd);
860 } else if(rlurdd.isEmpty()) {
861 GregorianCalendar gc = trans.org().expiration(null, Expiration.UserInRole);
863 return Result.err(Result.ERR_Policy,"Organzation does not grant Expiration for UserRole");
865 urdd.expires = gc.getTime();
867 Result<UserRoleDAO.Data> rurdd = urDAO.create(trans, urdd);
868 return Result.err(rurdd);
872 return Result.err(Result.ERR_Security,"Only the User can create User Permissions");
875 // Does Perm Type exist as a Namespace?
876 if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
877 return Result.err(Status.ERR_ConflictAlreadyExists,
878 "Permission Type exists as a Namespace");
881 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
884 public String get() {
885 return "Create Permission [" +
886 newPd.value.fullType() + '|' +
887 newPd.value.instance + '|' +
888 newPd.value.action + ']';
892 private Result<NsDAO.Data> nsd;
894 public Result<?> mayChange() {
896 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
902 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
903 if (nsr.notOKorIsEmpty()) {
904 return Result.err(nsr);
908 Result<String> rfc = func.createFuture(trans,fd.value,
909 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
914 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
917 newPd.value.instance,
920 return Result.err(rfc);
923 return func.createPerm(trans, newPd.value, true);
925 return Result.err(fd);
932 path = "/authz/perms/:type",
933 params = {"type|string|true"},
935 errorCodes = { 404,406 },
936 text = { "List All Permissions that match the :type element of the key" }
939 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
940 final Validator v = new ServiceValidator();
941 if (v.nullOrBlank("PermType", permType).err()) {
942 return Result.err(Status.ERR_BadData,v.errs());
945 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
947 return Result.err(rlpd);
950 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
951 // Result<NsDAO.Data> r;
952 // if ((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
954 PERMS perms = mapper.newInstance(API.PERMS);
955 if (!rlpd.isEmpty()) {
956 // Note: Mapper will restrict what can be viewed
957 return mapper.perms(trans, rlpd.value, perms, true);
959 return Result.ok(perms);
964 path = "/authz/perms/:type/:instance/:action",
965 params = {"type|string|true",
966 "instance|string|true",
967 "action|string|true"},
969 errorCodes = { 404,406 },
970 text = { "List Permissions that match key; :type, :instance and :action" }
973 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
974 final Validator v = new ServiceValidator();
975 if (v.nullOrBlank("PermType", type).err()
976 || v.nullOrBlank("PermInstance", instance).err()
977 || v.nullOrBlank("PermAction", action).err()) {
978 return Result.err(Status.ERR_BadData,v.errs());
981 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
983 return Result.err(rlpd);
986 PERMS perms = mapper.newInstance(API.PERMS);
987 if (!rlpd.isEmpty()) {
988 // Note: Mapper will restrict what can be viewed
989 return mapper.perms(trans, rlpd.value, perms, true);
991 return Result.ok(perms);
996 path = "/authz/perms/user/:user",
997 params = {"user|string|true"},
999 errorCodes = { 404,406 },
1000 text = { "List All Permissions that match user :user",
1001 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
1004 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
1005 final Validator v = new ServiceValidator();
1006 if (v.nullOrBlank("User", user).err()) {
1007 return Result.err(Status.ERR_BadData,v.errs());
1010 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,
1011 trans.requested(force));
1013 return Result.err(rlpd);
1016 PERMS perms = mapper.newInstance(API.PERMS);
1018 if (rlpd.isEmpty()) {
1019 return Result.ok(perms);
1021 // Note: Mapper will restrict what can be viewed
1022 // if user is the same as that which is looked up, no filtering is required
1023 return mapper.perms(trans, rlpd.value,
1025 !user.equals(trans.user()));
1030 path = "/authz/perms/user/:user/scope/:scope",
1031 params = {"user|string|true","scope|string|true"},
1033 errorCodes = { 404,406 },
1034 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
1035 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1036 "<p>'scope' must be expressed as NSs separated by ':'</p>"
1040 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
1041 final Validator v = new ServiceValidator();
1042 if (v.nullOrBlank("User", user).err()) {
1043 return Result.err(Status.ERR_BadData,v.errs());
1046 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
1048 return Result.err(rlpd);
1051 PERMS perms = mapper.newInstance(API.PERMS);
1053 if (rlpd.isEmpty()) {
1054 return Result.ok(perms);
1056 // Note: Mapper will restrict what can be viewed
1057 // if user is the same as that which is looked up, no filtering is required
1058 return mapper.perms(trans, rlpd.value,
1061 !user.equals(trans.user()));
1066 path = "/authz/perms/user/:user",
1067 params = {"user|string|true"},
1069 errorCodes = { 404,406 },
1070 text = { "List All Permissions that match user :user",
1071 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1073 "Present Queries as one or more Permissions (see ContentType Links below for format).",
1075 "If the Caller is Granted this specific Permission, and the Permission is valid",
1076 " for the User, it will be included in response Permissions, along with",
1077 " all the normal permissions on the 'GET' version of this call. If it is not",
1078 " valid, or Caller does not have permission to see, it will be removed from the list",
1080 " *Note: This design allows you to make one call for all expected permissions",
1081 " The permission to be included MUST be:",
1082 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1084 " com.att.myns.access|:ns|write",
1085 " com.att.myns.access|:role:myrole|create",
1086 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1091 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1092 PERMS perms = _perms;
1093 final Validator v = new ServiceValidator();
1094 if (v.nullOrBlank("User", user).err()) {
1095 return Result.err(Status.ERR_BadData,v.errs());
1099 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.requested(force));
1101 return Result.err(rlpd);
1105 1) See if allowed to query
1106 2) See if User is allowed
1108 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1109 if (in.isOKhasData()) {
1110 List<PermDAO.Data> out = rlpd.value;
1112 for (PermDAO.Data pdd : in.value) {
1114 if ("access".equals(pdd.type)) {
1115 Access access = Access.valueOf(pdd.action);
1116 String[] mdkey = Split.splitTrim(':',pdd.instance);
1117 if (mdkey.length>1) {
1118 String type = mdkey[1];
1119 if ("role".equals(type)) {
1120 if (mdkey.length>2) {
1121 RoleDAO.Data rdd = new RoleDAO.Data();
1124 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1126 } else if ("perm".equals(type)) {
1127 if (mdkey.length>4) { // also need instance/action
1128 PermDAO.Data p = new PermDAO.Data();
1131 p.instance=mdkey[3];
1133 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1135 } else if ("ns".equals(type)) {
1136 NsDAO.Data ndd = new NsDAO.Data();
1138 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1148 perms = mapper.newInstance(API.PERMS);
1149 if (rlpd.isEmpty()) {
1150 return Result.ok(perms);
1152 // Note: Mapper will restrict what can be viewed
1153 // if user is the same as that which is looked up, no filtering is required
1154 return mapper.perms(trans, rlpd.value,
1156 !user.equals(trans.user()));
1161 path = "/authz/perms/role/:role",
1162 params = {"role|string|true"},
1164 errorCodes = { 404,406 },
1165 text = { "List All Permissions that are granted to :role" }
1168 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1169 final Validator v = new ServiceValidator();
1170 if (v.nullOrBlank("Role", role).err()) {
1171 return Result.err(Status.ERR_BadData,v.errs());
1174 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1176 return Result.err(rrdd);
1179 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1181 return Result.err(r);
1184 PERMS perms = mapper.newInstance(API.PERMS);
1186 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1187 if (rlpd.isOKhasData()) {
1188 // Note: Mapper will restrict what can be viewed
1189 return mapper.perms(trans, rlpd.value, perms, true);
1191 return Result.ok(perms);
1196 path = "/authz/perms/ns/:ns",
1197 params = {"ns|string|true"},
1199 errorCodes = { 404,406 },
1200 text = { "List All Permissions that are in Namespace :ns" }
1203 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1204 final Validator v = new ServiceValidator();
1205 if (v.nullOrBlank("NS", ns).err()) {
1206 return Result.err(Status.ERR_BadData,v.errs());
1209 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1211 return Result.err(rnd);
1214 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1216 return Result.err(rnd);
1219 Result<List<PermDAO.Data>> rlpd = ques.permDAO().readNS(trans, ns);
1221 return Result.err(rlpd);
1224 PERMS perms = mapper.newInstance(API.PERMS);
1225 if (!rlpd.isEmpty()) {
1226 // Note: Mapper will restrict what can be viewed
1227 return mapper.perms(trans, rlpd.value,perms, true);
1229 return Result.ok(perms);
1234 path = "/authz/perm/:type/:instance/:action",
1235 params = {"type|string|true",
1236 "instance|string|true",
1237 "action|string|true"},
1239 errorCodes = { 404,406, 409 },
1240 text = { "Rename the Permission referenced by :type :instance :action, and "
1241 + "rename (copy/delete) to the Permission described in PermRequest" }
1244 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1245 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1246 final ServiceValidator v = new ServiceValidator();
1247 if (v.perm(newPd).err()) {
1248 return Result.err(Status.ERR_BadData,v.errs());
1251 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1252 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1253 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1256 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1257 Result<List<PermDAO.Data>> origRlpd = ques.permDAO().read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1259 if (origRlpd.notOKorIsEmpty()) {
1260 return Result.err(Status.ERR_PermissionNotFound,
1261 "Permission [%s|%s|%s] does not exist",
1262 origType,origInstance,origAction);
1265 PermDAO.Data origPd = origRlpd.value.get(0);
1267 if (!origPd.ns.equals(newPd.value.ns)) {
1268 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1269 "<new type> must start with [" + origPd.ns + "]");
1272 if ( origPd.type.equals(newPd.value.type) &&
1273 origPd.action.equals(newPd.value.action) &&
1274 origPd.instance.equals(newPd.value.instance) ) {
1275 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1278 Set<String> origRoles = origPd.roles(false);
1279 if (!origRoles.isEmpty()) {
1280 Set<String> roles = newPd.value.roles(true);
1281 for (String role : origPd.roles) {
1286 newPd.value.description = origPd.description;
1288 Result<Void> rv = null;
1290 rv = func.createPerm(trans, newPd.value, false);
1292 rv = func.deletePerm(trans, origPd, true, false);
1299 path = "/authz/perm",
1302 errorCodes = { 404,406 },
1303 text = { "Add Description Data to Perm" }
1306 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1307 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1308 final ServiceValidator v = new ServiceValidator();
1309 if (v.perm(pd).err()) {
1310 return Result.err(Status.ERR_BadData,v.errs());
1312 if (v.nullOrBlank("description", pd.value.description).err()) {
1313 return Result.err(Status.ERR_BadData,v.errs());
1315 final PermDAO.Data perm = pd.value;
1316 if (ques.permDAO().read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1317 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1318 perm.ns,perm.type,perm.instance,perm.action);
1321 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1322 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1323 perm.ns,perm.type,perm.instance,perm.action);
1326 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pd.value.ns);
1327 if (nsr.notOKorIsEmpty()) {
1328 return Result.err(nsr);
1331 Result<Void> rdr = ques.permDAO().addDescription(trans, perm.ns, perm.type, perm.instance,
1332 perm.action, perm.description);
1336 return Result.err(rdr);
1343 path = "/authz/role/perm",
1346 errorCodes = {403,404,406,409},
1347 text = { "Set a permission's roles to roles given" }
1351 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1352 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1353 if (updt.notOKorIsEmpty()) {
1354 return Result.err(updt);
1357 final ServiceValidator v = new ServiceValidator();
1358 if (v.perm(updt).err()) {
1359 return Result.err(Status.ERR_BadData,v.errs());
1362 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1364 return Result.err(nsd);
1367 // Read full set to get CURRENT values
1368 Result<List<PermDAO.Data>> rcurr = ques.permDAO().read(trans,
1371 updt.value.instance,
1374 if (rcurr.notOKorIsEmpty()) {
1375 return Result.err(Status.ERR_PermissionNotFound,
1376 "Permission [%s.%s|%s|%s] does not exist",
1377 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1380 // Create a set of Update Roles, which are in Internal Format
1381 Set<String> updtRoles = new HashSet<>();
1382 Result<NsSplit> nss;
1383 for (String role : updt.value.roles(false)) {
1384 nss = ques.deriveNsSplit(trans, role);
1386 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1388 trans.error().log(nss.errorString());
1392 Result<Void> rv = null;
1394 for (PermDAO.Data curr : rcurr.value) {
1395 Set<String> currRoles = curr.roles(false);
1396 // must add roles to this perm, and add this perm to each role
1397 // in the update, but not in the current
1398 for (String role : updtRoles) {
1399 if (!currRoles.contains(role)) {
1400 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1401 if (key.isOKhasData()) {
1402 Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, key.value);
1403 if (rrd.isOKhasData()) {
1404 for (RoleDAO.Data r : rrd.value) {
1405 rv = func.addPermToRole(trans, r, curr, false);
1406 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1407 return Result.err(rv);
1411 return Result.err(rrd);
1416 // similarly, must delete roles from this perm, and delete this perm from each role
1417 // in the update, but not in the current
1418 for (String role : currRoles) {
1419 if (!updtRoles.contains(role)) {
1420 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1421 if (key.isOKhasData()) {
1422 Result<List<RoleDAO.Data>> rdd = ques.roleDAO().read(trans, key.value);
1423 if (rdd.isOKhasData()) {
1424 for (RoleDAO.Data r : rdd.value) {
1425 rv = func.delPermFromRole(trans, r, curr, true);
1426 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1427 return Result.err(rv);
1435 return rv==null?Result.ok():rv;
1440 path = "/authz/perm",
1443 errorCodes = { 404,406 },
1444 text = { "Delete the Permission referenced by PermKey.",
1445 "You cannot normally delete a permission which is still granted to roles,",
1446 "however the \"force\" property allows you to do just that. To do this: Add",
1447 "'force=true' as a query parameter.",
1448 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1451 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1452 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1454 return Result.err(pd);
1456 final ServiceValidator v = new ServiceValidator();
1457 if (v.nullOrBlank(pd.value).err()) {
1458 return Result.err(Status.ERR_BadData,v.errs());
1460 final PermDAO.Data perm = pd.value;
1461 if (ques.permDAO().read(trans, perm).notOKorIsEmpty()) {
1462 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1463 perm.ns,perm.type,perm.instance,perm.action );
1466 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1469 public String get() {
1470 return "Delete Permission [" + perm.fullPerm() + ']';
1474 private Result<NsDAO.Data> nsd;
1476 public Result<?> mayChange() {
1478 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1486 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, perm.ns);
1487 if (nsr.notOKorIsEmpty()) {
1488 return Result.err(nsr);
1491 Result<String> rfc = func.createFuture(trans, fd.value,
1492 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1494 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1496 return Result.err(rfc);
1498 case Status.ACC_Now:
1499 return func.deletePerm(trans,perm,trans.requested(force), false);
1501 return Result.err(fd);
1507 path = "/authz/perm/:name/:type/:action",
1508 params = {"type|string|true",
1509 "instance|string|true",
1510 "action|string|true"},
1512 errorCodes = { 404,406 },
1513 text = { "Delete the Permission referenced by :type :instance :action",
1514 "You cannot normally delete a permission which is still granted to roles,",
1515 "however the \"force\" property allows you to do just that. To do this: Add",
1516 "'force=true' as a query parameter",
1517 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1520 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1521 final Validator v = new ServiceValidator();
1522 if (v.nullOrBlank("Type",type)
1523 .nullOrBlank("Instance",instance)
1524 .nullOrBlank("Action",action)
1526 return Result.err(Status.ERR_BadData,v.errs());
1529 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1531 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1533 return Result.err(pd);
1537 /***********************************
1539 ***********************************/
1542 path = "/authz/role",
1545 errorCodes = {403,404,406,409},
1548 "Roles are part of Namespaces",
1550 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1551 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1552 "Restrictions on Role Names:",
1553 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1554 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1555 "<li>role names are Case Sensitive</li></ul>",
1556 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1557 "<ul><li>'What Job Function does this represent?'</li>",
1558 "<li>'Does this person perform this Job Function?'</li></ul>" }
1562 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1563 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1564 // Does Perm Type exist as a Namespace?
1565 if(rd.value.name.isEmpty() || ques.nsDAO().read(trans, rd.value.fullName()).isOKhasData()) {
1566 return Result.err(Status.ERR_ConflictAlreadyExists,
1567 "Role exists as a Namespace");
1569 final ServiceValidator v = new ServiceValidator();
1570 if (v.role(rd).err()) {
1571 return Result.err(Status.ERR_BadData,v.errs());
1573 final RoleDAO.Data role = rd.value;
1574 if (ques.roleDAO().read(trans, role.ns, role.name).isOKhasData()) {
1575 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1578 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1581 public String get() {
1582 return "Create Role [" +
1583 rd.value.fullName() +
1588 private Result<NsDAO.Data> nsd;
1590 public Result<?> mayChange() {
1592 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1598 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1599 if (nsr.notOKorIsEmpty()) {
1600 return Result.err(nsr);
1605 Result<String> rfc = func.createFuture(trans, fd.value,
1606 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1608 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1612 return Result.err(rfc);
1614 case Status.ACC_Now:
1615 Result<RoleDAO.Data> rdr = ques.roleDAO().create(trans, role);
1619 return Result.err(rdr);
1622 return Result.err(fd);
1627 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1631 path = "/authz/roles/:role",
1632 params = {"role|string|true"},
1634 errorCodes = {404,406},
1635 text = { "List Roles that match :role",
1636 "Note: You must have permission to see any given role"
1640 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1641 final Validator v = new ServiceValidator();
1642 if (v.nullOrBlank("Role", role).err()) {
1643 return Result.err(Status.ERR_BadData,v.errs());
1646 // Determine if User can ask this question
1647 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1648 if (rrdd.isOKhasData()) {
1649 Result<NsDAO.Data> r;
1650 if ((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1651 return Result.err(r);
1654 return Result.err(rrdd);
1658 int query = role.indexOf('?');
1659 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1661 // Note: Mapper will restrict what can be viewed
1662 ROLES roles = mapper.newInstance(API.ROLES);
1663 return mapper.roles(trans, rlrd.value, roles, true);
1665 return Result.err(rlrd);
1670 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1674 path = "/authz/roles/user/:name",
1675 params = {"name|string|true"},
1677 errorCodes = {404,406},
1678 text = { "List all Roles that match user :name",
1679 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1680 "Note: You must have permission to see any given role"
1685 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1686 final Validator v = new ServiceValidator();
1687 if (v.nullOrBlank("User", user).err()) {
1688 return Result.err(Status.ERR_BadData,v.errs());
1691 ROLES roles = mapper.newInstance(API.ROLES);
1692 // Get list of roles per user, then add to Roles as we go
1693 Result<List<RoleDAO.Data>> rlrd;
1694 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
1695 if (rlurd.isOKhasData()) {
1696 for (UserRoleDAO.Data urd : rlurd.value ) {
1697 rlrd = ques.roleDAO().read(trans, urd.ns,urd.rname);
1698 // Note: Mapper will restrict what can be viewed
1699 // if user is the same as that which is looked up, no filtering is required
1700 if (rlrd.isOKhasData()) {
1701 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1705 return Result.ok(roles);
1710 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1714 path = "/authz/roles/ns/:ns",
1715 params = {"ns|string|true"},
1717 errorCodes = {404,406},
1718 text = { "List all Roles for the Namespace :ns",
1719 "Note: You must have permission to see any given role"
1724 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1725 final Validator v = new ServiceValidator();
1726 if (v.nullOrBlank("NS", ns).err()) {
1727 return Result.err(Status.ERR_BadData,v.errs());
1730 // check if user is allowed to view NS
1731 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1733 return Result.err(rnsd);
1735 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1737 return Result.err(rnsd);
1740 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1742 ROLES roles = mapper.newInstance(API.ROLES);
1743 // Get list of roles per user, then add to Roles as we go
1744 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readNS(trans, ns);
1746 if (!rlrd.isEmpty()) {
1747 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1748 mapper.roles(trans,rlrd.value,roles,false);
1750 return Result.ok(roles);
1752 return Result.err(rlrd);
1761 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1765 path = "/authz/roles/name/:name",
1766 params = {"name|string|true"},
1768 errorCodes = {404,406},
1769 text = { "List all Roles for only the Name of Role (without Namespace)",
1770 "Note: You must have permission to see any given role"
1774 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1775 final Validator v = new ServiceValidator();
1776 if (v.nullOrBlank("Name", name).err()) {
1777 return Result.err(Status.ERR_BadData,v.errs());
1780 // User Mapper to make sure user is allowed to view NS
1782 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1784 ROLES roles = mapper.newInstance(API.ROLES);
1785 // Get list of roles per user, then add to Roles as we go
1786 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readName(trans, name);
1788 if (!rlrd.isEmpty()) {
1789 // Note: Mapper will restrict what can be viewed
1790 mapper.roles(trans,rlrd.value,roles,true);
1792 return Result.ok(roles);
1794 return Result.err(rlrd);
1803 path = "/authz/roles/perm/:type/:instance/:action",
1804 params = {"type|string|true",
1805 "instance|string|true",
1806 "action|string|true"},
1808 errorCodes = {404,406},
1809 text = { "Find all Roles containing the given Permission." +
1810 "Permission consists of:",
1811 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1812 + "is being protected</li>",
1813 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1814 + " instance of the type</li>",
1815 "<li>action - what kind of action is allowed</li></ul>",
1816 "Notes: instance and action can be an *",
1817 " You must have permission to see any given role"
1822 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1823 final Validator v = new ServiceValidator();
1824 if (v.permType(type)
1825 .permInstance(instance)
1828 return Result.err(Status.ERR_BadData,v.errs());
1831 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1833 ROLES roles = mapper.newInstance(API.ROLES);
1834 // Get list of roles per user, then add to Roles as we go
1835 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1836 if (nsSplit.isOK()) {
1837 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1839 if ((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1840 return Result.err(res);
1843 Result<List<PermDAO.Data>> pdlr = ques.permDAO().read(trans, pdd);
1844 if (pdlr.isOK())for (PermDAO.Data pd : pdlr.value) {
1845 Result<List<RoleDAO.Data>> rlrd;
1846 for (String r : pd.roles) {
1847 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1849 rlrd = ques.roleDAO().read(trans, rs.value[0],rs.value[1]);
1850 // Note: Mapper will restrict what can be viewed
1851 if (rlrd.isOKhasData()) {
1852 mapper.roles(trans,rlrd.value,roles,true);
1858 return Result.ok(roles);
1866 path = "/authz/role",
1869 errorCodes = {404,406},
1870 text = { "Add Description Data to a Role" }
1874 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1875 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1876 final ServiceValidator v = new ServiceValidator();
1877 if (v.role(rd).err()) {
1878 return Result.err(Status.ERR_BadData,v.errs());
1880 if (v.nullOrBlank("description", rd.value.description).err()) {
1881 return Result.err(Status.ERR_BadData,v.errs());
1884 final RoleDAO.Data role = rd.value;
1885 if (ques.roleDAO().read(trans, role.ns, role.name).notOKorIsEmpty()) {
1886 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1889 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1890 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1893 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1894 if (nsr.notOKorIsEmpty()) {
1895 return Result.err(nsr);
1898 Result<Void> rdr = ques.roleDAO().addDescription(trans, role.ns, role.name, role.description);
1902 return Result.err(rdr);
1909 path = "/authz/role/perm",
1912 errorCodes = {403,404,406,409},
1913 text = { "Grant a Permission to a Role",
1914 "Permission consists of:",
1915 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1916 + "is being protected</li>",
1917 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1918 + " instance of the type</li>",
1919 "<li>action - what kind of action is allowed</li></ul>",
1920 "Note: instance and action can be an *",
1921 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1922 " ID is allowed to create. It will then grant",
1923 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1928 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1929 // Translate Request into Perm and Role Objects
1930 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1931 if (rpd.notOKorIsEmpty()) {
1932 return Result.err(rpd);
1934 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1935 if (rrd.notOKorIsEmpty()) {
1936 return Result.err(rrd);
1939 // Validate Role and Perm values
1940 final ServiceValidator v = new ServiceValidator();
1941 if (v.perm(rpd.value)
1944 return Result.err(Status.ERR_BadData,v.errs());
1947 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().read(trans, rrd.value.ns, rrd.value.name);
1948 if (rlrd.notOKorIsEmpty()) {
1949 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1952 // Check Status of Data in DB (does it exist)
1953 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, rpd.value.ns,
1954 rpd.value.type, rpd.value.instance, rpd.value.action);
1955 PermDAO.Data createPerm = null; // if not null, create first
1956 if (rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1957 if (trans.requested(force)) {
1958 // Remove roles from perm data object so we just create the perm here
1959 createPerm = rpd.value;
1960 createPerm.roles.clear();
1962 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1963 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1966 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1967 return Result.err(Status.ERR_ConflictAlreadyExists,
1968 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1969 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1970 rrd.value.ns,rrd.value.name
1976 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1979 public String get() {
1980 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1981 " to Role [" + rrd.value.fullName() + "]";
1985 private Result<NsDAO.Data> nsd;
1987 public Result<?> mayChange() {
1989 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1994 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rpd.value.ns);
1995 if (nsr.notOKorIsEmpty()) {
1996 return Result.err(nsr);
2000 Result<String> rfc = func.createFuture(trans,fd.value,
2001 rpd.value.fullPerm(),
2006 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2012 return Result.err(rfc);
2014 case Status.ACC_Now:
2015 Result<Void> rv = null;
2016 if (createPerm!=null) {// has been validated for creating
2017 rv = func.createPerm(trans, createPerm, false);
2019 if (rv==null || rv.isOK()) {
2020 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
2024 return Result.err(fd);
2030 * Delete Perms from Roles (UnGrant)
2032 * @param roleFullName
2037 path = "/authz/role/:role/perm",
2038 params = {"role|string|true"},
2040 errorCodes = {404,406},
2041 text = { "Ungrant a permission from Role :role" }
2045 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
2046 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
2047 if (updt.notOKorIsEmpty()) {
2048 return Result.err(updt);
2050 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
2051 if (rrd.notOKorIsEmpty()) {
2052 return Result.err(rrd);
2055 final ServiceValidator v = new ServiceValidator();
2056 if (v.nullOrBlank(updt.value)
2057 .nullOrBlank(rrd.value)
2059 return Result.err(Status.ERR_BadData,v.errs());
2062 return delPermFromRole(trans, updt.value,rrd.value, rreq);
2065 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
2066 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, pdd.ns, pdd.type,
2067 pdd.instance, pdd.action);
2069 if (rlpd.notOKorIsEmpty()) {
2070 return Result.err(Status.ERR_PermissionNotFound,
2071 "Permission [%s.%s|%s|%s] does not exist",
2072 pdd.ns,pdd.type,pdd.instance,pdd.action);
2075 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
2078 public String get() {
2079 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
2080 " from Role [" + rdd.fullName() + "]";
2084 private Result<NsDAO.Data> nsd;
2086 public Result<?> mayChange() {
2088 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2093 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pdd.ns);
2094 if (nsr.notOKorIsEmpty()) {
2095 return Result.err(nsr);
2099 Result<String> rfc = func.createFuture(trans,fd.value,
2106 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2112 return Result.err(rfc);
2114 case Status.ACC_Now:
2115 return func.delPermFromRole(trans, rdd, pdd, false);
2117 return Result.err(fd);
2124 path = "/authz/role/:role/perm/:type/:instance/:action",
2125 params = {"role|string|true",
2126 "perm type|string|true",
2127 "perm instance|string|true",
2128 "perm action|string|true"
2131 errorCodes = {404,406},
2132 text = { "Ungrant a single permission from Role :role with direct key" }
2136 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2137 Result<Data> rpns = ques.deriveNs(trans, type);
2138 if (rpns.notOKorIsEmpty()) {
2139 return Result.err(rpns);
2142 final Validator v = new ServiceValidator();
2144 .permType(rpns.value.name,rpns.value.parent)
2145 .permInstance(instance)
2148 return Result.err(Status.ERR_BadData,v.errs());
2151 Result<Data> rrns = ques.deriveNs(trans, role);
2152 if (rrns.notOKorIsEmpty()) {
2153 return Result.err(rrns);
2156 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, rrns.value.parent, rrns.value.name);
2157 if (rrd.notOKorIsEmpty()) {
2158 return Result.err(rrd);
2161 final Result<List<PermDAO.Data>> rpd = ques.permDAO().read(trans, rpns.value.parent, rpns.value.name, instance, action);
2162 if (rpd.notOKorIsEmpty()) {
2163 return Result.err(rpd);
2167 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2172 path = "/authz/role/:role",
2173 params = {"role|string|true"},
2175 errorCodes = {404,406},
2176 text = { "Delete the Role named :role"}
2180 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2181 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2182 if (rrdd.isOKhasData()) {
2183 final ServiceValidator v = new ServiceValidator();
2184 if (v.nullOrBlank(rrdd.value).err()) {
2185 return Result.err(Status.ERR_BadData,v.errs());
2187 return func.deleteRole(trans, rrdd.value, false, false);
2189 return Result.err(rrdd);
2195 path = "/authz/role",
2198 errorCodes = { 404,406 },
2199 text = { "Delete the Role referenced by RoleKey",
2200 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2201 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2202 "as a query parameter.",
2203 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2207 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2208 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2209 final ServiceValidator v = new ServiceValidator();
2211 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2213 if (v.nullOrBlank(rd.value).err()) {
2214 return Result.err(Status.ERR_BadData,v.errs());
2216 final RoleDAO.Data role = rd.value;
2217 if (ques.roleDAO().read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2218 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2221 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2222 () -> "Delete Role [" + role.fullName() + ']'
2223 + " and all attached user roles",
2225 private Result<NsDAO.Data> nsd;
2227 public Result<?> mayChange() {
2229 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2237 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
2238 if (nsr.notOKorIsEmpty()) {
2239 return Result.err(nsr);
2242 Result<String> rfc = func.createFuture(trans, fd.value,
2243 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2245 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2249 return Result.err(rfc);
2251 case Status.ACC_Now:
2252 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2254 return Result.err(fd);
2259 /***********************************
2261 ***********************************/
2262 private class MayCreateCred implements MayChange {
2263 private Result<NsDAO.Data> nsd;
2264 private AuthzTrans trans;
2265 private CredDAO.Data cred;
2266 private Executor exec;
2268 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2275 public Result<?> mayChange() {
2277 nsd = ques.validNSOfDomain(trans, cred.id);
2279 // is Ns of CredID valid?
2283 if (trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2286 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2287 if (rmc.isOKhasData()) {
2291 } catch (Exception e) {
2292 trans.warn().log(e);
2295 trans.warn().log(nsd.errorString());
2297 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2301 private class MayChangeCred implements MayChange {
2303 private Result<NsDAO.Data> nsd;
2304 private AuthzTrans trans;
2305 private CredDAO.Data cred;
2306 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
2312 public Result<?> mayChange() {
2313 // User can change himself (but not create)
2314 if (trans.user().equals(cred.id)) {
2318 nsd = ques.validNSOfDomain(trans, cred.id);
2320 // Get the Namespace
2322 if (ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
2325 String user[] = Split.split('.',trans.user());
2326 if (user.length>2) {
2327 String company = user[user.length-1] + '.' + user[user.length-2];
2328 if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) {
2333 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
2338 private final long DAY_IN_MILLIS = 24*3600*1000L;
2342 path = "/authn/cred",
2345 errorCodes = {403,404,406,409},
2346 text = { "A credential consists of:",
2347 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2348 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2349 "AB1234@myapp.att.com</li>",
2350 "<li>password - Company Policy Compliant Password</li></ul>",
2351 "Note: AAF does support multiple credentials with the same ID.",
2352 "Check with your organization if you have this implemented."
2356 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2357 final String cmdDescription = ("Create User Credential");
2358 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2361 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2362 if (rcred.isOKhasData()) {
2363 rcred = ques.userCredSetup(trans, rcred.value);
2365 final ServiceValidator v = new ServiceValidator();
2367 if (v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2368 return Result.err(Status.ERR_BadData,v.errs());
2372 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2373 Identity mechID = null;
2374 Organization org = trans.org();
2376 mechID = org.getIdentity(trans, rcred.value.id);
2377 } catch (Exception e1) {
2378 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2380 if (mechID==null || !mechID.isFound()) {
2381 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2384 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2385 if (nsr.notOKorIsEmpty()) {
2386 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2390 boolean firstID = false;
2393 CassExecutor exec = new CassExecutor(trans, func);
2394 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2395 if (rlcd.isOKhasData()) {
2396 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2397 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2400 for (CredDAO.Data curr : rlcd.value) {
2401 // May not use the same password in the list
2402 // Note: ASPR specifies character differences, but we don't actually store the
2403 // password to validate char differences.
2405 // byte[] rawCred = rcred.value.type==CredDAO.RAW?null:;
2407 rb = ques.userCredCheck(trans, curr, rcred.value.cred.array());
2409 return Result.err(rb);
2410 } else if (rb.value){
2411 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2412 } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
2413 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
2418 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2419 String theMechID = rcred.value.id;
2420 Boolean otherMechIDs = false;
2421 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2422 for (CredDAO.Data cd : ques.credDAO().readNS(trans,nsr.value.get(0).name).value) {
2423 if (!cd.id.equals(theMechID)) {
2424 otherMechIDs = true;
2429 // We can say "ID does not exist" here
2430 if ((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2431 return Result.err(Status.ERR_Denied, reason);
2434 } catch (Exception e) {
2435 return Result.err(e);
2439 mc = new MayCreateCred(trans, rcred.value, exec);
2441 final CredDAO.Data cdd = rcred.value;
2442 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2445 public String get() {
2446 return cmdDescription + " [" +
2449 + cdd.expires + ']';
2456 Result<String> rfc = func.createFuture(trans, fd.value,
2457 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2458 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2460 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2462 Integer.toString(rcred.value.type),
2463 rcred.value.expires.toString());
2465 return Result.err(rfc);
2467 case Status.ACC_Now:
2470 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
2471 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
2472 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
2473 // Note, we only do this on First time, because of possibility of
2474 // prematurely expiring a production id
2475 if (admins.isOKhasData() && !admins.value.contains(trans.user())) {
2476 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2479 } catch (Exception e) {
2480 trans.error().log(e, "While setting expiration to TempPassword");
2483 Result<?>udr = ques.credDAO().create(trans, rcred.value);
2487 return Result.err(udr);
2489 return Result.err(fd);
2493 return Result.err(rcred);
2502 path = "/authn/creds/ns/:ns",
2503 params = {"ns|string|true"},
2505 errorCodes = {403,404,406},
2506 text = { "Return all IDs in Namespace :ns"
2510 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2511 final Validator v = new ServiceValidator();
2512 if (v.ns(ns).err()) {
2513 return Result.err(Status.ERR_BadData,v.errs());
2516 // check if user is allowed to view NS
2517 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2519 return Result.err(rnd);
2521 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2523 return Result.err(rnd);
2526 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2528 USERS users = mapper.newInstance(API.USERS);
2529 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readNS(trans, ns);
2532 if (!rlcd.isEmpty()) {
2533 return mapper.cred(rlcd.value, users);
2535 return Result.ok(users);
2537 return Result.err(rlcd);
2547 path = "/authn/creds/id/:ns",
2548 params = {"id|string|true"},
2550 errorCodes = {403,404,406},
2551 text = { "Return all IDs in for ID"
2552 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2556 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2557 final Validator v = new ServiceValidator();
2558 if (v.nullOrBlank("ID",id).err()) {
2559 return Result.err(Status.ERR_BadData,v.errs());
2562 String ns = Question.domain2ns(id);
2563 // check if user is allowed to view NS
2564 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2566 return Result.err(rnd);
2568 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2570 return Result.err(rnd);
2573 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2575 USERS users = mapper.newInstance(API.USERS);
2576 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, id);
2579 if (!rlcd.isEmpty()) {
2580 return mapper.cred(rlcd.value, users);
2582 return Result.ok(users);
2584 return Result.err(rlcd);
2594 path = "/authn/certs/id/:id",
2595 params = {"id|string|true"},
2597 errorCodes = {403,404,406},
2598 text = { "Return Cert Info for ID"
2602 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2603 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2605 CERTS certs = mapper.newInstance(API.CERTS);
2606 Result<List<CertDAO.Data>> rlcd = ques.certDAO().readID(trans, id);
2609 if (!rlcd.isEmpty()) {
2610 return mapper.cert(rlcd.value, certs);
2612 return Result.ok(certs);
2614 return Result.err(rlcd);
2624 path = "/authn/cred",
2627 errorCodes = {300,403,404,406},
2628 text = { "Reset a Credential Password. If multiple credentials exist for this",
2629 "ID, you will need to specify which entry you are resetting in the",
2630 "CredRequest object"
2634 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
2635 final String cmdDescription = "Update User Credential";
2636 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2638 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2639 if (rcred.isOKhasData()) {
2640 rcred = ques.userCredSetup(trans, rcred.value);
2642 final ServiceValidator v = new ServiceValidator();
2644 if (v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2645 return Result.err(Status.ERR_BadData,v.errs());
2647 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2648 if (rlcd.notOKorIsEmpty()) {
2649 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2652 MayChange mc = new MayChangeCred(trans, rcred.value);
2653 Result<?> rmc = mc.mayChange();
2655 return Result.err(rmc);
2658 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2660 return Result.err(ri);
2662 int entry = ri.value;
2665 final CredDAO.Data cred = rcred.value;
2667 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2670 public String get() {
2671 return cmdDescription + " [" +
2674 + cred.expires + ']';
2679 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2680 if (nsr.notOKorIsEmpty()) {
2681 return Result.err(nsr);
2686 Result<String> rfc = func.createFuture(trans, fd.value,
2687 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2688 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2690 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2692 Integer.toString(rcred.value.type),
2693 rcred.value.expires.toString());
2695 return Result.err(rfc);
2697 case Status.ACC_Now:
2698 Result<?>udr = null;
2699 // If we are Resetting Password on behalf of someone else (am not the Admin)
2700 // use TempPassword Expiration time.
2702 if (ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2703 exp = Expiration.Password;
2705 exp = Expiration.TempPassword;
2708 Organization org = trans.org();
2709 CredDAO.Data current = rlcd.value.get(entry);
2710 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2711 if (current.expires.equals(rcred.value.expires)
2712 && rlcd.value.get(entry).type==rcred.value.type) {
2713 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2714 gc = Chrono.firstMomentOfDay(gc);
2715 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2716 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2718 rcred.value.expires = org.expiration(null,exp).getTime();
2721 udr = ques.credDAO().create(trans, rcred.value);
2723 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2729 return Result.err(udr);
2731 return Result.err(fd);
2734 return Result.err(rcred);
2742 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
2744 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
2746 if (lcd.size() > 1) {
2747 String inputOption = cr.getEntry();
2748 if (inputOption == null) {
2749 String message = selectCredFromList(lcd, false);
2750 Object[] variables = buildVariables(lcd);
2751 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2753 entry = Integer.parseInt(inputOption) - 1;
2755 if (entry < 0 || entry >= lcd.size()) {
2756 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2759 return Result.ok(entry);
2764 path = "/authn/cred/:days",
2765 params = {"days|string|true"},
2767 errorCodes = {300,403,404,406},
2768 text = { "Extend a Credential Expiration Date. The intention of this API is",
2769 "to avoid an outage in PROD due to a Credential expiring before it",
2770 "can be configured correctly. Measures are being put in place ",
2771 "so that this is not abused."
2775 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2776 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2778 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2779 Organization org = trans.org();
2780 final ServiceValidator v = new ServiceValidator();
2781 if (v.notOK(cred).err() ||
2782 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2783 v.user(org,cred.value.id).err()) {
2784 return Result.err(Status.ERR_BadData,v.errs());
2789 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2790 return Result.err(Status.ERR_Policy,reason);
2792 } catch (Exception e) {
2794 trans.error().log(e, msg="Could not contact Organization for User Validation");
2795 return Result.err(Status.ERR_Denied, msg);
2798 // Get the list of Cred Entries
2799 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2800 if (rlcd.notOKorIsEmpty()) {
2801 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2804 //Need to do the "Pick Entry" mechanism
2805 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2807 return Result.err(ri);
2810 CredDAO.Data found = rlcd.value.get(ri.value);
2811 CredDAO.Data cd = cred.value;
2812 // Copy over the cred
2814 cd.cred = found.cred;
2815 cd.other = found.other;
2816 cd.type = found.type;
2818 cd.notes = "Extended";
2819 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2822 cred = ques.credDAO().create(trans, cd);
2826 return Result.err(cred);
2832 private String[] buildVariables(List<CredDAO.Data> value) {
2833 // ensure credentials are sorted so we can fully automate Cred regression test
2834 Collections.sort(value, (cred1, cred2) -> cred1.expires.compareTo(cred2.expires));
2835 String [] vars = new String[value.size()+1];
2837 for (int i = 0; i < value.size(); i++) {
2838 vars[i+1] = value.get(i).id + " " + value.get(i).type
2839 + " |" + value.get(i).expires;
2844 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
2845 StringBuilder errMessage = new StringBuilder();
2846 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
2847 int numSpaces = value.get(0).id.length() - "Id".length();
2849 errMessage.append(userPrompt + '\n');
2850 errMessage.append(" Id");
2851 for (int i = 0; i < numSpaces; i++) {
2852 errMessage.append(' ');
2854 errMessage.append(" Type Expires" + '\n');
2855 for (int i=0;i<value.size();++i) {
2856 errMessage.append(" %s\n");
2858 errMessage.append("Run same command again with chosen entry as last parameter");
2860 return errMessage.toString();
2866 path = "/authn/cred",
2869 errorCodes = {300,403,404,406},
2870 text = { "Delete a Credential. If multiple credentials exist for this",
2871 "ID, you will need to specify which entry you are deleting in the",
2872 "CredRequest object."
2876 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2877 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2878 final Validator v = new ServiceValidator();
2879 if (v.nullOrBlank("cred", cred.value.id).err()) {
2880 return Result.err(Status.ERR_BadData,v.errs());
2883 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2884 if (rlcd.notOKorIsEmpty()) {
2885 // Empty Creds should have no user_roles.
2886 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2888 for (UserRoleDAO.Data data : rlurd.value) {
2889 ques.userRoleDAO().delete(trans, data, false);
2892 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2894 boolean isLastCred = rlcd.value.size()==1;
2896 MayChange mc = new MayChangeCred(trans,cred.value);
2897 Result<?> rmc = mc.mayChange();
2899 return Result.err(rmc);
2903 if (!trans.requested(force)) {
2904 if (rlcd.value.size() > 1) {
2905 CredRequest cr = (CredRequest)from;
2906 String inputOption = cr.getEntry();
2907 if (inputOption == null) {
2908 String message = selectCredFromList(rlcd.value, true);
2909 Object[] variables = buildVariables(rlcd.value);
2910 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2913 if (inputOption.length()>5) { // should be a date
2914 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2916 for (CredDAO.Data cd : rlcd.value) {
2917 if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2923 entry = Integer.parseInt(inputOption) - 1;
2925 } catch (NullPointerException e) {
2926 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2927 } catch (NumberFormatException e) {
2928 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2931 isLastCred = (entry==-1)?true:false;
2935 if (entry < -1 || entry >= rlcd.value.size()) {
2936 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2940 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2941 () -> "Delete Credential [" +
2946 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
2947 if (nsr.notOKorIsEmpty()) {
2948 return Result.err(nsr);
2953 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2954 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2957 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2959 return Result.err(rfc);
2961 case Status.ACC_Now:
2962 Result<?>udr = null;
2963 if (!trans.requested(force)) {
2964 if (entry<0 || entry >= rlcd.value.size()) {
2965 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
2967 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2969 for (CredDAO.Data curr : rlcd.value) {
2970 udr = ques.credDAO().delete(trans, curr, false);
2972 return Result.err(udr);
2977 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2979 for (UserRoleDAO.Data data : rlurd.value) {
2980 ques.userRoleDAO().delete(trans, data, false);
2985 return Result.err(Result.ERR_NotFound,"No User Data found");
2990 return Result.err(udr);
2992 return Result.err(fd);
2999 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
3000 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
3002 // Note: Mapper assigns RAW type
3003 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
3004 if (data.notOKorIsEmpty()) {
3005 return Result.err(data);
3007 CredDAO.Data cred = data.value; // of the Mapped Cred
3008 if (cred.cred==null) {
3009 return Result.err(Result.ERR_BadData,"No Password");
3011 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
3014 } catch (DAOException e) {
3015 trans.error().log(e,"Error looking up cred");
3016 return Result.err(Status.ERR_Denied,"Credential does not match");
3024 path = "/authn/basicAuth",
3027 errorCodes = { 403 },
3028 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
3029 + "Use /authn/validate instead\n"
3030 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
3031 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
3032 + "security, and 403 if it does not." }
3034 private void basicAuth() {
3035 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
3040 path = "/authn/validate",
3043 errorCodes = { 403 },
3044 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
3045 + "do more than BasicAuth as Credential types exp" }
3048 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
3049 //TODO how to make sure people don't use this in browsers? Do we care?
3050 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
3052 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
3053 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
3054 // Note: Only want to log problem, don't want to send back to end user
3058 trans.audit().log(rq.errorString());
3060 } catch (Exception e) {
3061 trans.warn().log(e);
3065 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
3068 /***********************************
3070 ***********************************/
3073 path = "/authz/userRole",
3076 errorCodes = {403,404,406,409},
3077 text = { "Create a UserRole relationship (add User to Role)",
3078 "A UserRole is an object Representation of membership of a Role for limited time.",
3079 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
3080 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
3081 "before Expirations expire. Namespace owners will be notified by email."
3085 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3086 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3088 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3089 if (urr.notOKorIsEmpty()) {
3090 return Result.err(urr);
3092 final UserRoleDAO.Data userRole = urr.value;
3094 final ServiceValidator v = new ServiceValidator();
3095 if (v.user_role(userRole).err() ||
3096 v.user(trans.org(), userRole.user).err()) {
3097 return Result.err(Status.ERR_BadData,v.errs());
3102 // Check if user can change first
3103 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3104 () -> "Add User [" + userRole.user + "] to Role [" +
3108 private Result<NsDAO.Data> nsd;
3110 public Result<?> mayChange() {
3112 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3113 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3118 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3119 if (nsr.notOKorIsEmpty()) {
3120 return Result.err(nsr);
3125 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3126 userRole.user, nsr.value, FUTURE_OP.C);
3128 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3133 return Result.err(rfc);
3135 case Status.ACC_Now:
3136 return func.addUserRole(trans, userRole);
3138 return Result.err(fd);
3146 * getUserRolesByRole
3150 path = "/authz/userRoles/role/:role",
3151 params = {"role|string|true"},
3153 errorCodes = {404,406},
3154 text = { "List all Users that are attached to Role specified in :role",
3158 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3159 final Validator v = new ServiceValidator();
3160 if (v.nullOrBlank("Role",role).err()) {
3161 return Result.err(Status.ERR_BadData,v.errs());
3164 Result<RoleDAO.Data> rrdd;
3165 rrdd = RoleDAO.Data.decode(trans,ques,role);
3167 return Result.err(rrdd);
3169 // May Requester see result?
3170 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3172 return Result.err(ns);
3175 // boolean filter = true;
3176 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3179 // Get list of roles per user, then add to Roles as we go
3180 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3181 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3183 for (UserRoleDAO.Data data : rlurd.value) {
3188 @SuppressWarnings("unchecked")
3189 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3190 // Checked for permission
3191 mapper.userRoles(trans, userSet, users);
3192 return Result.ok(users);
3195 * getUserRolesByRole
3199 path = "/authz/userRoles/user/:user",
3200 params = {"role|string|true"},
3202 errorCodes = {404,406},
3203 text = { "List all UserRoles for :user",
3207 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3208 final Validator v = new ServiceValidator();
3209 if (v.nullOrBlank("User",user).err()) {
3210 return Result.err(Status.ERR_BadData,v.errs());
3213 // Get list of roles per user, then add to Roles as we go
3214 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
3215 if (rlurd.notOK()) {
3216 return Result.err(rlurd);
3221 * 2) is User's Supervisor
3222 * 3) Has special global access =read permission
3224 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3227 String callingUser = trans.getUserPrincipal().getName();
3228 NsDAO.Data ndd = new NsDAO.Data();
3230 if (user.equals(callingUser)) {
3233 Organization org = trans.org();
3235 Identity orgID = org.getIdentity(trans, user);
3236 Identity manager = orgID==null?null:orgID.responsibleTo();
3237 if (orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3239 } else if (ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3244 } catch (OrganizationException e) {
3250 List<UserRoleDAO.Data> content;
3252 content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos
3254 for (UserRoleDAO.Data data : rlurd.value) {
3256 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3263 content = rlurd.value;
3267 @SuppressWarnings("unchecked")
3268 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3269 // Checked for permission
3270 mapper.userRoles(trans, content, users);
3271 return Result.ok(users);
3279 path = "/authz/userRole/extend/:user/:role",
3280 params = { "user|string|true",
3284 errorCodes = {403,404,406},
3285 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3286 "Requestor must be allowed to modify the role"
3290 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3291 Organization org = trans.org();
3292 final ServiceValidator v = new ServiceValidator();
3293 if (v.user(org, user)
3296 return Result.err(Status.ERR_BadData,v.errs());
3299 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3301 return Result.err(rrdd);
3304 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3305 boolean mayNotChange;
3306 if ((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3307 return Result.err(rcr);
3310 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO().read(trans, user,role);
3312 return Result.err(rr);
3314 for (UserRoleDAO.Data userRole : rr.value) {
3315 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3316 FutureDAO.Data fto = new FutureDAO.Data();
3317 fto.target=UserRoleDAO.TABLE;
3318 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3319 GregorianCalendar now = new GregorianCalendar();
3320 fto.start = now.getTime();
3321 fto.expires = org.expiration(now, Expiration.Future).getTime();
3323 fto.construct = userRole.bytify();
3324 } catch (IOException e) {
3325 trans.error().log(e, "Error while bytifying UserRole for Future");
3326 return Result.err(e);
3329 Result<String> rfc = func.createFuture(trans, fto,
3330 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3332 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3336 return Result.err(rfc);
3339 return func.extendUserRole(trans, userRole, false);
3342 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3347 path = "/authz/userRole/:user/:role",
3348 params = { "user|string|true",
3352 errorCodes = {403,404,406},
3353 text = { "Remove Role :role from User :user."
3357 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3358 Validator val = new ServiceValidator();
3359 if (val.nullOrBlank("User", usr)
3360 .nullOrBlank("Role", role).err()) {
3361 return Result.err(Status.ERR_BadData, val.errs());
3364 boolean mayNotChange;
3365 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3367 return Result.err(rrdd);
3370 RoleDAO.Data rdd = rrdd.value;
3371 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3373 // Make sure we don't delete the last owner of valid NS
3374 if (rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3375 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3378 if (mayNotChange=rns.notOK()) {
3379 if (!trans.requested(future)) {
3380 return Result.err(rns);
3384 Result<List<UserRoleDAO.Data>> rulr;
3385 if ((rulr=ques.userRoleDAO().read(trans, usr, role)).notOKorIsEmpty()) {
3386 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3387 + "Assigned to the Role [ " + role + " ]");
3390 UserRoleDAO.Data userRole = rulr.value.get(0);
3391 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3392 FutureDAO.Data fto = new FutureDAO.Data();
3393 fto.target=UserRoleDAO.TABLE;
3394 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3395 GregorianCalendar now = new GregorianCalendar();
3396 fto.start = now.getTime();
3397 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3399 Result<String> rfc = func.createFuture(trans, fto,
3400 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3402 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3406 return Result.err(rfc);
3409 return ques.userRoleDAO().delete(trans, rulr.value.get(0), false);
3415 path = "/authz/userRole/:user/:role",
3416 params = {"user|string|true",
3417 "role|string|true"},
3419 errorCodes = {403,404,406},
3420 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3424 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3425 final Validator v = new ServiceValidator();
3426 if (v.role(role).nullOrBlank("User", user).err()) {
3427 return Result.err(Status.ERR_BadData,v.errs());
3430 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3431 // if (ns.notOK()) return Result.err(ns);
3433 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3434 // May calling user see by virtue of the Role
3435 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3437 return Result.err(rrdd);
3439 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3441 return Result.err(rnd);
3444 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3445 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readUserInRole(trans, user, role);
3447 for (UserRoleDAO.Data data : rlurd.value) {
3452 @SuppressWarnings("unchecked")
3453 USERS users = (USERS) mapper.newInstance(API.USERS);
3454 mapper.users(trans, userSet, users);
3455 return Result.ok(users);
3460 path = "/authz/users/role/:role",
3461 params = {"user|string|true",
3462 "role|string|true"},
3464 errorCodes = {403,404,406},
3465 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3469 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3470 final Validator v = new ServiceValidator();
3471 if (v.nullOrBlank("Role",role).err()) {
3472 return Result.err(Status.ERR_BadData,v.errs());
3475 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3476 // if (ns.notOK()) return Result.err(ns);
3478 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3479 // May calling user see by virtue of the Role
3480 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3482 return Result.err(rrdd);
3485 boolean contactOnly = false;
3486 // Allow the request of any valid user to find the contact of the NS (Owner)
3487 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3489 if (Question.OWNER.equals(rrdd.value.name)) {
3492 return Result.err(rnd);
3496 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3497 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3499 for (UserRoleDAO.Data data : rlurd.value) {
3500 if (contactOnly) { //scrub data
3501 // Can't change actual object, or will mess up the cache.
3502 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3504 scrub.rname = data.rname;
3505 scrub.role = data.role;
3506 scrub.user = data.user;
3514 @SuppressWarnings("unchecked")
3515 USERS users = (USERS) mapper.newInstance(API.USERS);
3516 mapper.users(trans, userSet, users);
3517 return Result.ok(users);
3521 * getUsersByPermission
3525 path = "/authz/users/perm/:type/:instance/:action",
3526 params = { "type|string|true",
3527 "instance|string|true",
3528 "action|string|true"
3531 errorCodes = {404,406},
3532 text = { "List all Users that have Permission specified by :type :instance :action",
3536 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3537 final Validator v = new ServiceValidator();
3538 if (v.nullOrBlank("Type",type)
3539 .nullOrBlank("Instance",instance)
3540 .nullOrBlank("Action",action)
3542 return Result.err(Status.ERR_BadData,v.errs());
3545 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3547 return Result.err(nss);
3550 Result<List<NsDAO.Data>> nsd = ques.nsDAO().read(trans, nss.value.ns);
3552 return Result.err(nsd);
3555 boolean allInstance = ASTERIX.equals(instance);
3556 boolean allAction = ASTERIX.equals(action);
3557 // Get list of roles per Permission,
3558 // Then loop through Roles to get Users
3559 // Note: Use Sets to avoid processing or responding with Duplicates
3560 Set<String> roleUsed = new HashSet<>();
3561 Set<UserRoleDAO.Data> userSet = new HashSet<>();
3563 if (!nss.isEmpty()) {
3564 Result<List<PermDAO.Data>> rlp = ques.permDAO().readByType(trans, nss.value.ns, nss.value.name);
3565 if (rlp.isOKhasData()) {
3566 for (PermDAO.Data pd : rlp.value) {
3567 if ((allInstance || pd.instance.equals(instance)) &&
3568 (allAction || pd.action.equals(action))) {
3569 if (ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3570 for (String role : pd.roles) {
3571 if (!roleUsed.contains(role)) { // avoid evaluating Role many times
3573 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role.replace('|', '.'));
3574 if (rlurd.isOKhasData()) {
3575 for (UserRoleDAO.Data urd : rlurd.value) {
3586 @SuppressWarnings("unchecked")
3587 USERS users = (USERS) mapper.newInstance(API.USERS);
3588 mapper.users(trans, userSet, users);
3589 return Result.ok(users);
3592 /***********************************
3594 ***********************************/
3596 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3597 final Validator v = new ServiceValidator();
3598 if (v.nullOrBlank("User",user).err()) {
3599 return Result.err(Status.ERR_BadData,v.errs());
3602 Result<NsDAO.Data> rnd;
3603 // Users may look at their own data
3604 if (trans.user().equals(user)) {
3605 // Users may look at their own data
3607 int at = user.indexOf('@');
3608 if (at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3609 NsDAO.Data nsd = new NsDAO.Data();
3610 nsd.name = Question.domain2ns(user);
3611 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3613 return Result.err(rnd);
3616 rnd = ques.validNSOfDomain(trans, user);
3618 return Result.err(rnd);
3621 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3623 return Result.err(rnd);
3627 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readByUser(trans, user, yyyymm);
3629 return Result.err(resp);
3631 return mapper.history(trans, resp.value,sort);
3635 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3636 final Validator v = new ServiceValidator();
3637 if (v.nullOrBlank("Role",role).err()) {
3638 return Result.err(Status.ERR_BadData,v.errs());
3641 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3643 return Result.err(rrdd);
3646 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3648 return Result.err(rnd);
3650 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, role, "role", yyyymm);
3652 return Result.err(resp);
3654 return mapper.history(trans, resp.value,sort);
3658 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3659 final Validator v = new ServiceValidator();
3660 if (v.nullOrBlank("Type",type)
3662 return Result.err(Status.ERR_BadData,v.errs());
3665 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3666 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3668 return Result.err(rnd);
3671 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3673 return Result.err(rnd);
3675 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3677 return Result.err(resp);
3679 return mapper.history(trans, resp.value,sort);
3683 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3684 final Validator v = new ServiceValidator();
3685 if (v.nullOrBlank("NS",ns)
3687 return Result.err(Status.ERR_BadData,v.errs());
3690 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3692 return Result.err(rnd);
3694 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3696 return Result.err(rnd);
3699 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, ns, "ns", yyyymm);
3701 return Result.err(resp);
3703 return mapper.history(trans, resp.value,sort);
3706 /***********************************
3708 ***********************************/
3710 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3711 return createOrUpdateDelegate(trans, base, Question.Access.create);
3715 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3716 return createOrUpdateDelegate(trans, base, Question.Access.write);
3720 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3721 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3722 final ServiceValidator v = new ServiceValidator();
3723 if (v.delegate(trans.org(),rd).err()) {
3724 return Result.err(Status.ERR_BadData,v.errs());
3727 final DelegateDAO.Data dd = rd.value;
3729 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO().read(trans, dd);
3730 if (access==Access.create && ddr.isOKhasData()) {
3731 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3732 } else if (access!=Access.create && ddr.notOKorIsEmpty()) {
3733 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3735 Result<Void> rv = ques.mayUser(trans, dd, access);
3740 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3742 StringBuilder sb = new StringBuilder();
3743 sb.append(access.name());
3744 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3745 sb.append("Delegate ");
3746 sb.append(access==Access.create?"[":"to [");
3747 sb.append(rd.value.delegate);
3748 sb.append("] for [");
3749 sb.append(rd.value.user);
3751 return sb.toString();
3754 return Result.ok(); // Validate in code above
3759 Result<String> rfc = func.createFuture(trans, fd.value,
3760 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3762 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3765 return Result.err(rfc);
3767 case Status.ACC_Now:
3768 if (access==Access.create) {
3769 Result<DelegateDAO.Data> rdr = ques.delegateDAO().create(trans, dd);
3773 return Result.err(rdr);
3776 return ques.delegateDAO().update(trans, dd);
3779 return Result.err(fd);
3784 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3785 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3786 final Validator v = new ServiceValidator();
3787 if (v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3788 return Result.err(Status.ERR_BadData,v.errs());
3791 Result<List<DelegateDAO.Data>> ddl;
3792 if ((ddl=ques.delegateDAO().read(trans, rd.value)).notOKorIsEmpty()) {
3793 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3795 final DelegateDAO.Data dd = ddl.value.get(0);
3796 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3801 return ques.delegateDAO().delete(trans, dd, false);
3805 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3806 DelegateDAO.Data dd = new DelegateDAO.Data();
3807 final Validator v = new ServiceValidator();
3808 if (v.nullOrBlank("User", userName).err()) {
3809 return Result.err(Status.ERR_BadData,v.errs());
3812 Result<List<DelegateDAO.Data>> ddl;
3813 if ((ddl=ques.delegateDAO().read(trans, dd)).notOKorIsEmpty()) {
3814 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3816 dd = ddl.value.get(0);
3817 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3822 return ques.delegateDAO().delete(trans, dd, false);
3826 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
3827 final Validator v = new ServiceValidator();
3828 if (v.nullOrBlank("User", user).err()) {
3829 return Result.err(Status.ERR_BadData,v.errs());
3832 DelegateDAO.Data ddd = new DelegateDAO.Data();
3834 ddd.delegate = null;
3835 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3837 return Result.err(rv);
3840 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
3842 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().read(trans, user);
3844 if (dbDelgs.isOKhasData()) {
3845 return mapper.delegate(dbDelgs.value);
3847 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
3855 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
3856 final Validator v = new ServiceValidator();
3857 if (v.nullOrBlank("Delegate", delegate).err()) {
3858 return Result.err(Status.ERR_BadData,v.errs());
3861 DelegateDAO.Data ddd = new DelegateDAO.Data();
3862 ddd.user = delegate;
3863 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3865 return Result.err(rv);
3868 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
3870 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().readByDelegate(trans, delegate);
3872 if (dbDelgs.isOKhasData()) {
3873 return mapper.delegate(dbDelgs.value);
3875 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
3882 /***********************************
3884 ***********************************/
3885 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
3887 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
3888 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
3890 return Result.err(rlad);
3892 int numApprs = rlad.value.size();
3894 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
3896 int numProcessed = 0;
3897 String user = trans.user();
3899 Result<List<ApprovalDAO.Data>> curr;
3900 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
3901 for (ApprovalDAO.Data updt : rlad.value) {
3902 if (updt.ticket!=null) {
3903 curr = ques.approvalDAO().readByTicket(trans, updt.ticket);
3904 if (curr.isOKhasData()) {
3905 final List<ApprovalDAO.Data> add = curr.value;
3906 // Store a Pre-Lookup
3907 apprByTicket = (trans1, noop) -> add;
3909 } else if (updt.id!=null) {
3910 curr = ques.approvalDAO().read(trans, updt);
3911 } else if (updt.approver!=null) {
3912 curr = ques.approvalDAO().readByApprover(trans, updt.approver);
3914 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
3917 if (curr.isOKhasData()) {
3918 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<>();
3919 Map<UUID, FutureDAO.Data> futureCache = new HashMap<>();
3920 FutureDAO.Data hasDeleted = new FutureDAO.Data();
3922 for (ApprovalDAO.Data cd : curr.value) {
3923 if ("pending".equals(cd.status)) {
3924 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
3926 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
3927 String delegator = cd.approver;
3928 if (updt.id!=null ||
3929 (updt.ticket!=null && user.equals(cd.approver)) ||
3930 (updt.ticket!=null && delegatedAction)) {
3931 if (updt.ticket.equals(cd.ticket)) {
3932 Changed ch = new Changed();
3933 cd.id = ch.changed(cd.id,updt.id);
3934 // cd.ticket = changed(cd.ticket,updt.ticket);
3935 cd.user = ch.changed(cd.user,updt.user);
3936 cd.approver = ch.changed(cd.approver,updt.approver);
3937 cd.type = ch.changed(cd.type,updt.type);
3938 cd.status = ch.changed(cd.status,updt.status);
3939 cd.memo = ch.changed(cd.memo,updt.memo);
3940 cd.operation = ch.changed(cd.operation,updt.operation);
3941 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
3942 // if (updt.status.equals("denied")) {
3943 // cd.last_notified = null;
3945 if (cd.ticket!=null) {
3946 FutureDAO.Data fdd = futureCache.get(cd.ticket);
3947 if (fdd==null) { // haven't processed ticket yet
3948 Result<FutureDAO.Data> rfdd = ques.futureDAO().readPrimKey(trans, cd.ticket);
3950 fdd = rfdd.value; // null is ok
3954 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
3956 if (fdd==hasDeleted) { // YES, by Object
3958 cd.status = "ticketDeleted";
3959 ch.hasChanged(true);
3961 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
3963 trans.info().printf("Approval Status %s is not actionable",cd.status);
3964 } else if (apprByTicket!=null) {
3965 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
3969 if (delegatedAction) {
3970 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
3972 futureCache.put(cd.ticket, hasDeleted);
3976 ch.hasChanged(true);
3977 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
3978 futureCache.put(cd.ticket, hasDeleted);
3983 trans.info().log(rv.toString());
3990 if (ch.hasChanged()) {
3991 ques.approvalDAO().update(trans, cd, true);
4000 if (numApprs==numProcessed) {
4003 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
4007 private static class Changed {
4008 private boolean hasChanged = false;
4010 public<T> T changed(T src, T proposed) {
4011 if (proposed==null || (src!=null && src.equals(proposed))) {
4018 public void hasChanged(boolean b) {
4022 public boolean hasChanged() {
4028 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
4029 final Validator v = new ServiceValidator();
4030 if (v.nullOrBlank("User", user).err()) {
4031 return Result.err(Status.ERR_BadData,v.errs());
4034 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByUser(trans, user);
4036 return mapper.approvals(rapd.value);
4038 return Result.err(rapd);
4043 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
4044 final Validator v = new ServiceValidator();
4045 if (v.nullOrBlank("Ticket", ticket).err()) {
4046 return Result.err(Status.ERR_BadData,v.errs());
4050 uuid = UUID.fromString(ticket);
4051 } catch (IllegalArgumentException e) {
4052 return Result.err(Status.ERR_BadData,e.getMessage());
4055 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByTicket(trans, uuid);
4057 return mapper.approvals(rapd.value);
4059 return Result.err(rapd);
4064 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
4065 final Validator v = new ServiceValidator();
4066 if (v.nullOrBlank("Approver", approver).err()) {
4067 return Result.err(Status.ERR_BadData,v.errs());
4070 List<ApprovalDAO.Data> listRapds = new ArrayList<>();
4072 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO().readByApprover(trans, approver);
4073 if (myRapd.notOK()) {
4074 return Result.err(myRapd);
4077 listRapds.addAll(myRapd.value);
4079 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO().readByDelegate(trans, approver);
4080 if (delegatedFor.isOK()) {
4081 for (DelegateDAO.Data dd : delegatedFor.value) {
4082 if (dd.expires.after(new Date())) {
4083 String delegator = dd.user;
4084 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByApprover(trans, delegator);
4086 for (ApprovalDAO.Data d : rapd.value) {
4087 if (!d.user.equals(trans.user())) {
4096 return mapper.approvals(listRapds);
4100 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4103 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4104 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4105 return ques.clearCache(trans,cname);
4107 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4108 trans.user(),ROOT_NS,CACHE,cname);
4112 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4115 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4116 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4117 Result<Void> v=null;
4118 for (int i: segment) {
4119 v=ques.cacheClear(trans,cname,i);
4125 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4126 trans.user(),ROOT_NS,CACHE,cname);
4130 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4133 public void dbReset(AuthzTrans trans) {
4134 ques.historyDAO().reportPerhapsReset(trans, null);