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;
45 import java.util.concurrent.TimeUnit;
47 import javax.servlet.http.HttpServletRequest;
49 import org.onap.aaf.auth.common.Define;
50 import org.onap.aaf.auth.dao.DAOException;
51 import org.onap.aaf.auth.dao.cached.CachedPermDAO;
52 import org.onap.aaf.auth.dao.cached.CachedRoleDAO;
53 import org.onap.aaf.auth.dao.cached.CachedUserRoleDAO;
54 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
55 import org.onap.aaf.auth.dao.cass.CertDAO;
56 import org.onap.aaf.auth.dao.cass.CredDAO;
57 import org.onap.aaf.auth.dao.cass.DelegateDAO;
58 import org.onap.aaf.auth.dao.cass.FutureDAO;
59 import org.onap.aaf.auth.dao.cass.HistoryDAO;
60 import org.onap.aaf.auth.dao.cass.Namespace;
61 import org.onap.aaf.auth.dao.cass.NsDAO;
62 import org.onap.aaf.auth.dao.cass.NsDAO.Data;
63 import org.onap.aaf.auth.dao.cass.NsSplit;
64 import org.onap.aaf.auth.dao.cass.NsType;
65 import org.onap.aaf.auth.dao.cass.PermDAO;
66 import org.onap.aaf.auth.dao.cass.RoleDAO;
67 import org.onap.aaf.auth.dao.cass.Status;
68 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
69 import org.onap.aaf.auth.dao.hl.CassExecutor;
70 import org.onap.aaf.auth.dao.hl.Function;
71 import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP;
72 import org.onap.aaf.auth.dao.hl.Function.Lookup;
73 import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
74 import org.onap.aaf.auth.dao.hl.PermLookup;
75 import org.onap.aaf.auth.dao.hl.Question;
76 import org.onap.aaf.auth.dao.hl.Question.Access;
77 import org.onap.aaf.auth.env.AuthzTrans;
78 import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE;
79 import org.onap.aaf.auth.layer.Result;
80 import org.onap.aaf.auth.org.Executor;
81 import org.onap.aaf.auth.org.Organization;
82 import org.onap.aaf.auth.org.Organization.Expiration;
83 import org.onap.aaf.auth.org.Organization.Identity;
84 import org.onap.aaf.auth.org.Organization.Policy;
85 import org.onap.aaf.auth.org.OrganizationException;
86 import org.onap.aaf.auth.rserv.doc.ApiDoc;
87 import org.onap.aaf.auth.service.mapper.Mapper;
88 import org.onap.aaf.auth.service.mapper.Mapper.API;
89 import org.onap.aaf.auth.service.validation.ServiceValidator;
90 import org.onap.aaf.auth.validation.Validator;
91 import org.onap.aaf.cadi.aaf.Defaults;
92 import org.onap.aaf.cadi.principal.BasicPrincipal;
93 import org.onap.aaf.cadi.util.FQI;
94 import org.onap.aaf.misc.env.Env;
95 import org.onap.aaf.misc.env.TimeTaken;
96 import org.onap.aaf.misc.env.util.Chrono;
97 import org.onap.aaf.misc.env.util.Split;
99 import aaf.v2_0.CredRequest;
102 * AuthzCassServiceImpl implements AuthzCassService for
117 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
118 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
120 private static final String TWO_SPACE = " ";
121 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
123 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
125 private static final String ASTERIX = "*";
126 private static final String CACHE = "cache";
127 private static final String ROOT_NS = Define.ROOT_NS();
128 private static final String ROOT_COMPANY = Define.ROOT_COMPANY();
130 private final Question ques;
131 private final Function func;
133 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
134 this.ques = question;
135 func = new Function(trans, question);
136 this.mapper = mapper;
140 /***********************************
142 ***********************************/
145 * @throws DAOException
146 * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
153 errorCodes = { 403,404,406,409 },
154 text = { "Namespace consists of: ",
155 "<ul><li>name - What you want to call this Namespace</li>",
156 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
157 "regarding this Namespace. Companies have Policies as to who may take on ",
158 "this Responsibility. Separate multiple identities with commas</li>",
159 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
160 "including creating Roles, Permissions and Credentials. Separate multiple ",
161 "identities with commas</li></ul>",
162 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
163 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
164 "be an admin of com.myCompany or com"
168 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
169 final Result<Namespace> rnamespace = mapper.ns(trans, from);
170 final ServiceValidator v = new ServiceValidator();
171 if (v.ns(rnamespace).err()) {
172 return Result.err(Status.ERR_BadData,v.errs());
174 final Namespace namespace = rnamespace.value;
175 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
176 if (parentNs.notOK()) {
177 return Result.err(parentNs);
180 // Note: Data validate occurs in func.createNS
181 if (namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
182 return func.createNS(trans, namespace, false);
185 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
188 public String get() {
189 return "Create Namespace [" + namespace.name + ']';
193 private Result<NsDAO.Data> rnd;
195 public Result<?> mayChange() {
197 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
204 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
206 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
208 return Result.err(rfc);
211 return func.createNS(trans, namespace, false);
213 return Result.err(fd);
219 path = "/authz/ns/:ns/admin/:id",
220 params = { "ns|string|true",
224 errorCodes = { 403,404,406,409 },
225 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
226 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
229 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
230 return func.addUserRole(trans, id, ns,Question.ADMIN);
235 path = "/authz/ns/:ns/admin/:id",
236 params = { "ns|string|true",
240 errorCodes = { 403,404 },
241 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
242 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
245 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
246 return func.delAdmin(trans,ns,id);
251 path = "/authz/ns/:ns/responsible/:id",
252 params = { "ns|string|true",
256 errorCodes = { 403,404,406,409 },
257 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
258 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
261 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
262 return func.addUserRole(trans,id,ns,Question.OWNER);
267 path = "/authz/ns/:ns/responsible/:id",
268 params = { "ns|string|true",
272 errorCodes = { 403,404 },
273 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
274 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
275 "Note: A namespace must have at least 1 responsible party"
279 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
280 return func.delOwner(trans,ns,id);
284 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
288 path = "/authz/ns/:ns/attrib/:key/:value",
289 params = { "ns|string|true",
291 "value|string|true"},
293 errorCodes = { 403,404,406,409 },
295 "Create an attribute in the Namespace",
296 "You must be given direct permission for key by AAF"
300 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
301 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
304 final Validator v = new ServiceValidator();
305 if (v.ns(ns).err() ||
307 v.value(value).err()) {
308 return Result.err(Status.ERR_BadData,v.errs());
311 // Check if exists already
312 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
313 if (rlnsd.notOKorIsEmpty()) {
314 return Result.err(rlnsd);
316 NsDAO.Data nsd = rlnsd.value.get(0);
318 // Check for Existence
319 if (nsd.attrib.get(key)!=null) {
320 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
323 // Check if User may put
324 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
325 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
326 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
330 nsd.attrib.put(key, value);
331 ques.nsDAO().dao().attribAdd(trans,ns,key,value);
332 ques.nsDAO().invalidate(trans, nsd);
341 path = "/authz/ns/attrib/:key",
342 params = { "key|string|true" },
344 errorCodes = { 403,404 },
346 "Read Attributes for Namespace"
350 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
352 final Validator v = new ServiceValidator();
353 if (v.nullOrBlank("Key",key).err()) {
354 return Result.err(Status.ERR_BadData,v.errs());
358 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
359 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
360 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
363 Result<Set<String>> rsd = ques.nsDAO().dao().readNsByAttrib(trans, key);
365 return Result.err(rsd);
367 return mapper().keys(rsd.value);
373 path = "/authz/ns/:ns/attrib/:key/:value",
374 params = { "ns|string|true",
377 errorCodes = { 403,404 },
379 "Update Value on an existing attribute in the Namespace",
380 "You must be given direct permission for key by AAF"
384 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
385 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
388 final Validator v = new ServiceValidator();
389 if (v.ns(ns).err() ||
391 v.value(value).err()) {
392 return Result.err(Status.ERR_BadData,v.errs());
395 // Check if exists already (NS must exist)
396 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
397 if (rlnsd.notOKorIsEmpty()) {
398 return Result.err(rlnsd);
400 NsDAO.Data nsd = rlnsd.value.get(0);
402 // Check for Existence
403 if (nsd.attrib.get(key)==null) {
404 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
407 // Check if User may put
408 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
409 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
410 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
414 nsd.attrib.put(key, value);
415 ques.nsDAO().invalidate(trans, nsd);
416 return ques.nsDAO().update(trans,nsd);
425 path = "/authz/ns/:ns/attrib/:key",
426 params = { "ns|string|true",
429 errorCodes = { 403,404 },
431 "Delete an attribute in the Namespace",
432 "You must be given direct permission for key by AAF"
436 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
437 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
440 final Validator v = new ServiceValidator();
441 if (v.nullOrBlank("NS",ns).err() ||
442 v.nullOrBlank("Key",key).err()) {
443 return Result.err(Status.ERR_BadData,v.errs());
446 // Check if exists already
447 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
448 if (rlnsd.notOKorIsEmpty()) {
449 return Result.err(rlnsd);
451 NsDAO.Data nsd = rlnsd.value.get(0);
453 // Check for Existence
454 if (nsd.attrib.get(key)==null) {
455 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
458 // Check if User may del
459 if (!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
460 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
464 nsd.attrib.remove(key);
465 ques.nsDAO().dao().attribRemove(trans,ns,key);
466 ques.nsDAO().invalidate(trans, nsd);
475 path = "/authz/nss/:id",
476 params = { "id|string|true" },
478 errorCodes = { 404,406 },
480 "Lists the Owner(s), Admin(s), Description, and Attributes of Namespace :id",
484 public Result<NSS> getNSbyName(AuthzTrans trans, String ns, boolean includeExpired) {
485 final Validator v = new ServiceValidator();
486 if (v.nullOrBlank("NS", ns).err()) {
487 return Result.err(Status.ERR_BadData,v.errs());
490 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, ns);
492 if (rlnd.isEmpty()) {
493 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
495 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
497 return Result.err(rnd);
501 Namespace namespace = new Namespace(rnd.value);
502 Result<List<String>> rd = func.getOwners(trans, namespace.name, includeExpired);
504 namespace.owner = rd.value;
506 rd = func.getAdmins(trans, namespace.name, includeExpired);
508 namespace.admin = rd.value;
511 NSS nss = mapper.newInstance(API.NSS);
512 return mapper.nss(trans, namespace, nss);
514 return Result.err(rlnd);
520 path = "/authz/nss/admin/:id",
521 params = { "id|string|true" },
523 errorCodes = { 403,404 },
524 text = { "Lists all Namespaces where Identity :id is an Admin",
525 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
529 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
530 final Validator v = new ServiceValidator();
531 if (v.nullOrBlank("User", user).err()) {
532 return Result.err(Status.ERR_BadData, v.errs());
535 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
537 return Result.err(rn);
540 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
542 NSS nss = mapper.newInstance(API.NSS);
543 // Note: "loadNamespace" already validates view of Namespace
544 return mapper.nss(trans, rn.value, nss);
549 path = "/authz/nss/either/:id",
550 params = { "id|string|true" },
552 errorCodes = { 403,404 },
553 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
554 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
558 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
559 final Validator v = new ServiceValidator();
560 if (v.nullOrBlank("User", user).err()) {
561 return Result.err(Status.ERR_BadData, v.errs());
564 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
566 return Result.err(rn);
569 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
571 NSS nss = mapper.newInstance(API.NSS);
572 // Note: "loadNamespace" already validates view of Namespace
573 return mapper.nss(trans, rn.value, nss);
576 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
577 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO().readByUser(trans, user);
578 if (urd.notOKorIsEmpty()) {
579 return Result.err(urd);
581 Map<String, Namespace> lm = new HashMap<>();
582 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<>();
583 for (UserRoleDAO.Data urdd : urd.value) {
585 if (endsWith==null || urdd.role.endsWith(endsWith)) {
586 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
587 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
589 Namespace namespace = lm.get(nsd.value.name);
590 if (namespace==null) {
591 namespace = new Namespace(nsd.value);
592 lm.put(namespace.name,namespace);
594 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
596 namespace.admin=rls.value;
599 rls = func.getOwners(trans, namespace.name, false);
601 namespace.owner=rls.value;
605 } else { // Shortened version. Only Namespace Info available from Role.
606 if (Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
607 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
608 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
610 Namespace namespace = lm.get(nsd.value.name);
611 if (namespace==null) {
613 namespace = other.remove(nsd.value.name);
615 if (namespace==null) {
616 namespace = new Namespace(nsd.value);
617 namespace.admin=new ArrayList<>();
618 namespace.owner=new ArrayList<>();
620 if (endsWith==null || urdd.role.endsWith(endsWith)) {
621 lm.put(namespace.name,namespace);
623 other.put(namespace.name,namespace);
626 if (Question.OWNER.equals(urdd.rname)) {
627 namespace.owner.add(urdd.user);
629 namespace.admin.add(urdd.user);
635 return Result.ok(lm.values());
640 path = "/authz/nss/responsible/:id",
641 params = { "id|string|true" },
643 errorCodes = { 403,404 },
644 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
645 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
649 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
650 final Validator v = new ServiceValidator();
651 if (v.nullOrBlank("User", user).err()) {
652 return Result.err(Status.ERR_BadData, v.errs());
654 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
656 return Result.err(rn);
659 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
661 NSS nss = mapper.newInstance(API.NSS);
662 // Note: "loadNamespace" prevalidates
663 return mapper.nss(trans, rn.value, nss);
668 path = "/authz/nss/children/:id",
669 params = { "id|string|true" },
671 errorCodes = { 403,404 },
672 text = { "Lists all Child Namespaces of Namespace :id",
673 "Note: This is not a cached read"
677 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
678 final Validator v = new ServiceValidator();
679 if (v.nullOrBlank("NS", parent).err()) {
680 return Result.err(Status.ERR_BadData,v.errs());
683 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
685 return Result.err(rnd);
687 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
689 return Result.err(rnd);
692 Set<Namespace> lm = new HashSet<>();
693 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().dao().getChildren(trans, parent);
695 if (rlnd.isEmpty()) {
696 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
698 for (NsDAO.Data ndd : rlnd.value) {
699 Namespace namespace = new Namespace(ndd);
700 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
702 namespace.admin=rls.value;
705 rls = func.getOwners(trans, namespace.name, false);
707 namespace.owner=rls.value;
712 NSS nss = mapper.newInstance(API.NSS);
713 return mapper.nss(trans,lm, nss);
715 return Result.err(rlnd);
725 errorCodes = { 403,404,406 },
726 text = { "Replace the Current Description of a Namespace with a new one"
730 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
731 final Result<Namespace> nsd = mapper.ns(trans, from);
732 final ServiceValidator v = new ServiceValidator();
733 if (v.ns(nsd).err()) {
734 return Result.err(Status.ERR_BadData,v.errs());
736 if (v.nullOrBlank("description", nsd.value.description).err()) {
737 return Result.err(Status.ERR_BadData,v.errs());
740 Namespace namespace = nsd.value;
741 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, namespace.name);
743 if (rlnd.notOKorIsEmpty()) {
744 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
747 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
748 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
751 Result<Void> rdr = ques.nsDAO().dao().addDescription(trans, namespace.name, namespace.description);
755 return Result.err(rdr);
761 * @throws DAOException
762 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
766 path = "/authz/ns/:ns",
767 params = { "ns|string|true" },
769 errorCodes = { 403,404,424 },
770 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
771 "are still credentials associated with them, but they can be deleted by setting ",
772 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
773 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
774 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
775 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
776 + "at or below Application Scope"
780 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
781 return func.deleteNS(trans, ns);
785 /***********************************
787 ***********************************/
791 * @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)
795 path = "/authz/perm",
798 errorCodes = {403,404,406,409},
799 text = { "Permission consists of:",
800 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
801 + "is being protected</li>",
802 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
803 + " instance of the type</li>",
804 "<li>action - what kind of action is allowed</li></ul>",
805 "Note: instance and action can be an *"
809 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
810 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
812 final ServiceValidator v = new ServiceValidator();
813 if (v.perm(newPd).err()) {
814 return Result.err(Status.ERR_BadData,v.errs());
817 // User Permission mechanism
818 if(newPd.value.ns.indexOf('@')>0) {
819 PermDAO.Data pdd = newPd.value;
820 if(trans.user().equals(newPd.value.ns)) {
821 CachedPermDAO permDAO = ques.permDAO();
822 Result<List<PermDAO.Data>> rlpdd = permDAO.read(trans, pdd);
824 return Result.err(rlpdd);
826 if(!rlpdd.isEmpty()) {
827 return Result.err(Result.ERR_ConflictAlreadyExists,"Permission already exists");
830 RoleDAO.Data rdd = new RoleDAO.Data();
834 pdd.roles(true).add(rdd.fullName());
835 Result<PermDAO.Data> rpdd = permDAO.create(trans, pdd);
837 return Result.err(rpdd);
840 CachedRoleDAO roleDAO = ques.roleDAO();
841 Result<List<RoleDAO.Data>> rlrdd = roleDAO.read(trans, rdd);
843 return Result.err(rlrdd);
845 if(!rlrdd.isEmpty()) {
846 rdd = rlrdd.value.get(0);
850 String eperm = pdd.encode();
851 rdd.perms(true).add(eperm);
852 Result<Void> rv = roleDAO.update(trans, rdd);
857 CachedUserRoleDAO urDAO = ques.userRoleDAO();
858 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
859 urdd.user = trans.user();
861 urdd.rname = rdd.name;
862 urdd.role = rdd.fullName();
863 Result<List<UserRoleDAO.Data>> rlurdd = urDAO.read(trans, urdd);
865 return Result.err(rlrdd);
866 } else if(rlurdd.isEmpty()) {
867 GregorianCalendar gc = trans.org().expiration(null, Expiration.UserInRole);
869 return Result.err(Result.ERR_Policy,"Organzation does not grant Expiration for UserRole");
871 urdd.expires = gc.getTime();
873 Result<UserRoleDAO.Data> rurdd = urDAO.create(trans, urdd);
874 return Result.err(rurdd);
878 return Result.err(Result.ERR_Security,"Only the User can create User Permissions");
881 // Does Perm Type exist as a Namespace?
882 if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
883 return Result.err(Status.ERR_ConflictAlreadyExists,
884 "Permission Type exists as a Namespace");
887 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
890 public String get() {
891 return "Create Permission [" +
892 newPd.value.fullType() + '|' +
893 newPd.value.instance + '|' +
894 newPd.value.action + ']';
898 private Result<NsDAO.Data> nsd;
900 public Result<?> mayChange() {
902 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
908 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
909 if (nsr.notOKorIsEmpty()) {
910 return Result.err(nsr);
914 Result<String> rfc = func.createFuture(trans,fd.value,
915 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
920 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
923 newPd.value.instance,
926 return Result.err(rfc);
929 return func.createPerm(trans, newPd.value, true);
931 return Result.err(fd);
938 path = "/authz/perms/:type",
939 params = {"type|string|true"},
941 errorCodes = { 404,406 },
942 text = { "List All Permissions that match the :type element of the key" }
945 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
946 final Validator v = new ServiceValidator();
947 if (v.nullOrBlank("PermType", permType).err()) {
948 return Result.err(Status.ERR_BadData,v.errs());
951 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
953 return Result.err(rlpd);
956 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
957 // Result<NsDAO.Data> r;
958 // if ((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
960 PERMS perms = mapper.newInstance(API.PERMS);
961 if (!rlpd.isEmpty()) {
962 // Note: Mapper will restrict what can be viewed
963 return mapper.perms(trans, rlpd.value, perms, true);
965 return Result.ok(perms);
970 path = "/authz/perms/:type/:instance/:action",
971 params = {"type|string|true",
972 "instance|string|true",
973 "action|string|true"},
975 errorCodes = { 404,406 },
976 text = { "List Permissions that match key; :type, :instance and :action" }
979 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
980 final Validator v = new ServiceValidator();
981 if (v.nullOrBlank("PermType", type).err()
982 || v.nullOrBlank("PermInstance", instance).err()
983 || v.nullOrBlank("PermAction", action).err()) {
984 return Result.err(Status.ERR_BadData,v.errs());
987 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
989 return Result.err(rlpd);
992 PERMS perms = mapper.newInstance(API.PERMS);
993 if (!rlpd.isEmpty()) {
994 // Note: Mapper will restrict what can be viewed
995 return mapper.perms(trans, rlpd.value, perms, true);
997 return Result.ok(perms);
1002 path = "/authz/perms/user/:user",
1003 params = {"user|string|true"},
1005 errorCodes = { 404,406 },
1006 text = { "List All Permissions that match user :user",
1007 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
1010 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
1011 final Validator v = new ServiceValidator();
1012 if (v.nullOrBlank("User", user).err()) {
1013 return Result.err(Status.ERR_BadData,v.errs());
1016 PermLookup pl = PermLookup.get(trans,ques,user);
1017 Result<List<PermDAO.Data>> rlpd = pl.getPerms(trans.requested(force));
1019 return Result.err(rlpd);
1022 PERMS perms = mapper.newInstance(API.PERMS);
1024 if (rlpd.isEmpty()) {
1025 return Result.ok(perms);
1027 // Note: Mapper will restrict what can be viewed
1028 // if user is the same as that which is looked up, no filtering is required
1029 return mapper.perms(trans, rlpd.value,
1031 !user.equals(trans.user()));
1036 path = "/authz/perms/user/:user/scope/:scope",
1037 params = {"user|string|true","scope|string|true"},
1039 errorCodes = { 404,406 },
1040 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
1041 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1042 "<p>'scope' must be expressed as NSs separated by ':'</p>"
1046 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
1047 final Validator v = new ServiceValidator();
1048 if (v.nullOrBlank("User", user).err()) {
1049 return Result.err(Status.ERR_BadData,v.errs());
1052 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
1054 return Result.err(rlpd);
1057 PERMS perms = mapper.newInstance(API.PERMS);
1059 if (rlpd.isEmpty()) {
1060 return Result.ok(perms);
1062 // Note: Mapper will restrict what can be viewed
1063 // if user is the same as that which is looked up, no filtering is required
1064 return mapper.perms(trans, rlpd.value,
1067 !user.equals(trans.user()));
1072 path = "/authz/perms/user/:user",
1073 params = {"user|string|true"},
1075 errorCodes = { 404,406 },
1076 text = { "List All Permissions that match user :user",
1077 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1079 "Present Queries as one or more Permissions (see ContentType Links below for format).",
1081 "If the Caller is Granted this specific Permission, and the Permission is valid",
1082 " for the User, it will be included in response Permissions, along with",
1083 " all the normal permissions on the 'GET' version of this call. If it is not",
1084 " valid, or Caller does not have permission to see, it will be removed from the list",
1086 " *Note: This design allows you to make one call for all expected permissions",
1087 " The permission to be included MUST be:",
1088 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1090 " com.att.myns.access|:ns|write",
1091 " com.att.myns.access|:role:myrole|create",
1092 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1097 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1098 PERMS perms = _perms;
1099 final Validator v = new ServiceValidator();
1100 if (v.nullOrBlank("User", user).err()) {
1101 return Result.err(Status.ERR_BadData,v.errs());
1105 PermLookup pl = PermLookup.get(trans,ques,user);
1106 Result<List<PermDAO.Data>> rlpd = pl.getPerms(trans.requested(force));
1108 return Result.err(rlpd);
1112 1) See if allowed to query
1113 2) See if User is allowed
1115 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1116 if (in.isOKhasData()) {
1117 List<PermDAO.Data> out = rlpd.value;
1119 for (PermDAO.Data pdd : in.value) {
1121 if ("access".equals(pdd.type)) {
1122 Access access = Access.valueOf(pdd.action);
1123 String[] mdkey = Split.splitTrim(':',pdd.instance);
1124 if (mdkey.length>1) {
1125 String type = mdkey[1];
1126 if ("role".equals(type)) {
1127 if (mdkey.length>2) {
1128 RoleDAO.Data rdd = new RoleDAO.Data();
1131 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1133 } else if ("perm".equals(type)) {
1134 if (mdkey.length>4) { // also need instance/action
1135 PermDAO.Data p = new PermDAO.Data();
1138 p.instance=mdkey[3];
1140 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1142 } else if ("ns".equals(type)) {
1143 NsDAO.Data ndd = new NsDAO.Data();
1145 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1155 perms = mapper.newInstance(API.PERMS);
1156 if (rlpd.isEmpty()) {
1157 return Result.ok(perms);
1159 // Note: Mapper will restrict what can be viewed
1160 // if user is the same as that which is looked up, no filtering is required
1161 return mapper.perms(trans, rlpd.value,
1163 !user.equals(trans.user()));
1168 path = "/authz/perms/role/:role",
1169 params = {"role|string|true"},
1171 errorCodes = { 404,406 },
1172 text = { "List All Permissions that are granted to :role" }
1175 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1176 final Validator v = new ServiceValidator();
1177 if (v.nullOrBlank("Role", role).err()) {
1178 return Result.err(Status.ERR_BadData,v.errs());
1181 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1183 return Result.err(rrdd);
1186 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1188 return Result.err(r);
1191 PERMS perms = mapper.newInstance(API.PERMS);
1193 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1194 if (rlpd.isOKhasData()) {
1195 // Note: Mapper will restrict what can be viewed
1196 return mapper.perms(trans, rlpd.value, perms, true);
1198 return Result.ok(perms);
1203 path = "/authz/perms/ns/:ns",
1204 params = {"ns|string|true"},
1206 errorCodes = { 404,406 },
1207 text = { "List All Permissions that are in Namespace :ns" }
1210 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1211 final Validator v = new ServiceValidator();
1212 if (v.nullOrBlank("NS", ns).err()) {
1213 return Result.err(Status.ERR_BadData,v.errs());
1216 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1218 return Result.err(rnd);
1221 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1223 return Result.err(rnd);
1226 Result<List<PermDAO.Data>> rlpd = ques.permDAO().readNS(trans, ns);
1228 return Result.err(rlpd);
1231 PERMS perms = mapper.newInstance(API.PERMS);
1232 if (!rlpd.isEmpty()) {
1233 // Note: Mapper will restrict what can be viewed
1234 return mapper.perms(trans, rlpd.value,perms, true);
1236 return Result.ok(perms);
1241 path = "/authz/perm/:type/:instance/:action",
1242 params = {"type|string|true",
1243 "instance|string|true",
1244 "action|string|true"},
1246 errorCodes = { 404,406, 409 },
1247 text = { "Rename the Permission referenced by :type :instance :action, and "
1248 + "rename (copy/delete) to the Permission described in PermRequest" }
1251 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1252 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1253 final ServiceValidator v = new ServiceValidator();
1254 if (v.perm(newPd).err()) {
1255 return Result.err(Status.ERR_BadData,v.errs());
1258 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1259 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1260 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1263 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1264 Result<List<PermDAO.Data>> origRlpd = ques.permDAO().read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1266 if (origRlpd.notOKorIsEmpty()) {
1267 return Result.err(Status.ERR_PermissionNotFound,
1268 "Permission [%s|%s|%s] does not exist",
1269 origType,origInstance,origAction);
1272 PermDAO.Data origPd = origRlpd.value.get(0);
1274 if (!origPd.ns.equals(newPd.value.ns)) {
1275 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1276 "<new type> must start with [" + origPd.ns + "]");
1279 if ( origPd.type.equals(newPd.value.type) &&
1280 origPd.action.equals(newPd.value.action) &&
1281 origPd.instance.equals(newPd.value.instance) ) {
1282 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1285 Set<String> origRoles = origPd.roles(false);
1286 if (!origRoles.isEmpty()) {
1287 Set<String> roles = newPd.value.roles(true);
1288 for (String role : origPd.roles) {
1293 newPd.value.description = origPd.description;
1295 Result<Void> rv = null;
1297 rv = func.createPerm(trans, newPd.value, false);
1299 rv = func.deletePerm(trans, origPd, true, false);
1306 path = "/authz/perm",
1309 errorCodes = { 404,406 },
1310 text = { "Add Description Data to Perm" }
1313 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1314 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1315 final ServiceValidator v = new ServiceValidator();
1316 if (v.perm(pd).err()) {
1317 return Result.err(Status.ERR_BadData,v.errs());
1319 if (v.nullOrBlank("description", pd.value.description).err()) {
1320 return Result.err(Status.ERR_BadData,v.errs());
1322 final PermDAO.Data perm = pd.value;
1323 if (ques.permDAO().read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1324 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1325 perm.ns,perm.type,perm.instance,perm.action);
1328 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1329 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1330 perm.ns,perm.type,perm.instance,perm.action);
1333 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pd.value.ns);
1334 if (nsr.notOKorIsEmpty()) {
1335 return Result.err(nsr);
1338 Result<Void> rdr = ques.permDAO().addDescription(trans, perm.ns, perm.type, perm.instance,
1339 perm.action, perm.description);
1343 return Result.err(rdr);
1350 path = "/authz/role/perm",
1353 errorCodes = {403,404,406,409},
1354 text = { "Set a permission's roles to roles given" }
1358 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1359 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1360 if (updt.notOKorIsEmpty()) {
1361 return Result.err(updt);
1364 final ServiceValidator v = new ServiceValidator();
1365 if (v.perm(updt).err()) {
1366 return Result.err(Status.ERR_BadData,v.errs());
1369 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1371 return Result.err(nsd);
1374 // Read full set to get CURRENT values
1375 Result<List<PermDAO.Data>> rcurr = ques.permDAO().read(trans,
1378 updt.value.instance,
1381 if (rcurr.notOKorIsEmpty()) {
1382 return Result.err(Status.ERR_PermissionNotFound,
1383 "Permission [%s.%s|%s|%s] does not exist",
1384 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1387 // Create a set of Update Roles, which are in Internal Format
1388 Set<String> updtRoles = new HashSet<>();
1389 Result<NsSplit> nss;
1390 for (String role : updt.value.roles(false)) {
1391 nss = ques.deriveNsSplit(trans, role);
1393 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1395 trans.error().log(nss.errorString());
1399 Result<Void> rv = null;
1401 for (PermDAO.Data curr : rcurr.value) {
1402 Set<String> currRoles = curr.roles(false);
1403 // must add roles to this perm, and add this perm to each role
1404 // in the update, but not in the current
1405 for (String role : updtRoles) {
1406 if (!currRoles.contains(role)) {
1407 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1408 if (key.isOKhasData()) {
1409 Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, key.value);
1410 if (rrd.isOKhasData()) {
1411 for (RoleDAO.Data r : rrd.value) {
1412 rv = func.addPermToRole(trans, r, curr, false);
1413 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1414 return Result.err(rv);
1418 return Result.err(rrd);
1423 // similarly, must delete roles from this perm, and delete this perm from each role
1424 // in the update, but not in the current
1425 for (String role : currRoles) {
1426 if (!updtRoles.contains(role)) {
1427 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1428 if (key.isOKhasData()) {
1429 Result<List<RoleDAO.Data>> rdd = ques.roleDAO().read(trans, key.value);
1430 if (rdd.isOKhasData()) {
1431 for (RoleDAO.Data r : rdd.value) {
1432 rv = func.delPermFromRole(trans, r, curr, true);
1433 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1434 return Result.err(rv);
1442 return rv==null?Result.ok():rv;
1447 path = "/authz/perm",
1450 errorCodes = { 404,406 },
1451 text = { "Delete the Permission referenced by PermKey.",
1452 "You cannot normally delete a permission which is still granted to roles,",
1453 "however the \"force\" property allows you to do just that. To do this: Add",
1454 "'force=true' as a query parameter.",
1455 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1458 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1459 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1461 return Result.err(pd);
1463 final ServiceValidator v = new ServiceValidator();
1464 if (v.nullOrBlank(pd.value).err()) {
1465 return Result.err(Status.ERR_BadData,v.errs());
1467 final PermDAO.Data perm = pd.value;
1468 if (ques.permDAO().read(trans, perm).notOKorIsEmpty()) {
1469 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1470 perm.ns,perm.type,perm.instance,perm.action );
1473 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1476 public String get() {
1477 return "Delete Permission [" + perm.fullPerm() + ']';
1481 private Result<NsDAO.Data> nsd;
1483 public Result<?> mayChange() {
1485 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1493 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, perm.ns);
1494 if (nsr.notOKorIsEmpty()) {
1495 return Result.err(nsr);
1498 Result<String> rfc = func.createFuture(trans, fd.value,
1499 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1501 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1503 return Result.err(rfc);
1505 case Status.ACC_Now:
1506 return func.deletePerm(trans,perm,trans.requested(force), false);
1508 return Result.err(fd);
1514 path = "/authz/perm/:name/:type/:action",
1515 params = {"type|string|true",
1516 "instance|string|true",
1517 "action|string|true"},
1519 errorCodes = { 404,406 },
1520 text = { "Delete the Permission referenced by :type :instance :action",
1521 "You cannot normally delete a permission which is still granted to roles,",
1522 "however the \"force\" property allows you to do just that. To do this: Add",
1523 "'force=true' as a query parameter",
1524 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1527 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1528 final Validator v = new ServiceValidator();
1529 if (v.nullOrBlank("Type",type)
1530 .nullOrBlank("Instance",instance)
1531 .nullOrBlank("Action",action)
1533 return Result.err(Status.ERR_BadData,v.errs());
1536 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1538 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1540 return Result.err(pd);
1544 /***********************************
1546 ***********************************/
1549 path = "/authz/role",
1552 errorCodes = {403,404,406,409},
1555 "Roles are part of Namespaces",
1557 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1558 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1559 "Restrictions on Role Names:",
1560 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1561 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1562 "<li>role names are Case Sensitive</li></ul>",
1563 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1564 "<ul><li>'What Job Function does this represent?'</li>",
1565 "<li>'Does this person perform this Job Function?'</li></ul>" }
1569 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1570 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1571 // Does Perm Type exist as a Namespace?
1572 if(rd.value.name.isEmpty() || ques.nsDAO().read(trans, rd.value.fullName()).isOKhasData()) {
1573 return Result.err(Status.ERR_ConflictAlreadyExists,
1574 "Role exists as a Namespace");
1576 final ServiceValidator v = new ServiceValidator();
1577 if (v.role(rd).err()) {
1578 return Result.err(Status.ERR_BadData,v.errs());
1580 final RoleDAO.Data role = rd.value;
1581 if (ques.roleDAO().read(trans, role.ns, role.name).isOKhasData()) {
1582 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1585 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1588 public String get() {
1589 return "Create Role [" +
1590 rd.value.fullName() +
1595 private Result<NsDAO.Data> nsd;
1597 public Result<?> mayChange() {
1599 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1605 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1606 if (nsr.notOKorIsEmpty()) {
1607 return Result.err(nsr);
1612 Result<String> rfc = func.createFuture(trans, fd.value,
1613 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1615 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1619 return Result.err(rfc);
1621 case Status.ACC_Now:
1622 Result<RoleDAO.Data> rdr = ques.roleDAO().create(trans, role);
1626 return Result.err(rdr);
1629 return Result.err(fd);
1634 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1638 path = "/authz/roles/:role",
1639 params = {"role|string|true"},
1641 errorCodes = {404,406},
1642 text = { "List Roles that match :role",
1643 "Note: You must have permission to see any given role"
1647 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1648 final Validator v = new ServiceValidator();
1649 if (v.nullOrBlank("Role", role).err()) {
1650 return Result.err(Status.ERR_BadData,v.errs());
1653 // Determine if User can ask this question
1654 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1655 if (rrdd.isOKhasData()) {
1656 Result<NsDAO.Data> r;
1657 if ((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1658 return Result.err(r);
1661 return Result.err(rrdd);
1665 int query = role.indexOf('?');
1666 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1668 // Note: Mapper will restrict what can be viewed
1669 ROLES roles = mapper.newInstance(API.ROLES);
1670 return mapper.roles(trans, rlrd.value, roles, true);
1672 return Result.err(rlrd);
1677 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1681 path = "/authz/roles/user/:name",
1682 params = {"name|string|true"},
1684 errorCodes = {404,406},
1685 text = { "List all Roles that match user :name",
1686 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1687 "Note: You must have permission to see any given role"
1692 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1693 final Validator v = new ServiceValidator();
1694 if (v.nullOrBlank("User", user).err()) {
1695 return Result.err(Status.ERR_BadData,v.errs());
1698 ROLES roles = mapper.newInstance(API.ROLES);
1699 // Get list of roles per user, then add to Roles as we go
1700 Result<List<RoleDAO.Data>> rlrd;
1701 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
1702 if (rlurd.isOKhasData()) {
1703 for (UserRoleDAO.Data urd : rlurd.value ) {
1704 rlrd = ques.roleDAO().read(trans, urd.ns,urd.rname);
1705 // Note: Mapper will restrict what can be viewed
1706 // if user is the same as that which is looked up, no filtering is required
1707 if (rlrd.isOKhasData()) {
1708 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1712 return Result.ok(roles);
1717 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1721 path = "/authz/roles/ns/:ns",
1722 params = {"ns|string|true"},
1724 errorCodes = {404,406},
1725 text = { "List all Roles for the Namespace :ns",
1726 "Note: You must have permission to see any given role"
1731 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1732 final Validator v = new ServiceValidator();
1733 if (v.nullOrBlank("NS", ns).err()) {
1734 return Result.err(Status.ERR_BadData,v.errs());
1737 // check if user is allowed to view NS
1738 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1740 return Result.err(rnsd);
1742 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1744 return Result.err(rnsd);
1747 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1749 ROLES roles = mapper.newInstance(API.ROLES);
1750 // Get list of roles per user, then add to Roles as we go
1751 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readNS(trans, ns);
1753 if (!rlrd.isEmpty()) {
1754 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1755 mapper.roles(trans,rlrd.value,roles,false);
1757 return Result.ok(roles);
1759 return Result.err(rlrd);
1768 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1772 path = "/authz/roles/name/:name",
1773 params = {"name|string|true"},
1775 errorCodes = {404,406},
1776 text = { "List all Roles for only the Name of Role (without Namespace)",
1777 "Note: You must have permission to see any given role"
1781 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1782 final Validator v = new ServiceValidator();
1783 if (v.nullOrBlank("Name", name).err()) {
1784 return Result.err(Status.ERR_BadData,v.errs());
1787 // User Mapper to make sure user is allowed to view NS
1789 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1791 ROLES roles = mapper.newInstance(API.ROLES);
1792 // Get list of roles per user, then add to Roles as we go
1793 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readName(trans, name);
1795 if (!rlrd.isEmpty()) {
1796 // Note: Mapper will restrict what can be viewed
1797 mapper.roles(trans,rlrd.value,roles,true);
1799 return Result.ok(roles);
1801 return Result.err(rlrd);
1810 path = "/authz/roles/perm/:type/:instance/:action",
1811 params = {"type|string|true",
1812 "instance|string|true",
1813 "action|string|true"},
1815 errorCodes = {404,406},
1816 text = { "Find all Roles containing the given Permission." +
1817 "Permission consists of:",
1818 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1819 + "is being protected</li>",
1820 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1821 + " instance of the type</li>",
1822 "<li>action - what kind of action is allowed</li></ul>",
1823 "Notes: instance and action can be an *",
1824 " You must have permission to see any given role"
1829 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1830 final Validator v = new ServiceValidator();
1831 if (v.permType(type)
1832 .permInstance(instance)
1835 return Result.err(Status.ERR_BadData,v.errs());
1838 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1840 ROLES roles = mapper.newInstance(API.ROLES);
1841 // Get list of roles per user, then add to Roles as we go
1842 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1843 if (nsSplit.isOK()) {
1844 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1846 if ((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1847 return Result.err(res);
1850 Result<List<PermDAO.Data>> pdlr = ques.permDAO().read(trans, pdd);
1851 if (pdlr.isOK())for (PermDAO.Data pd : pdlr.value) {
1852 Result<List<RoleDAO.Data>> rlrd;
1853 for (String r : pd.roles) {
1854 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1856 rlrd = ques.roleDAO().read(trans, rs.value[0],rs.value[1]);
1857 // Note: Mapper will restrict what can be viewed
1858 if (rlrd.isOKhasData()) {
1859 mapper.roles(trans,rlrd.value,roles,true);
1865 return Result.ok(roles);
1873 path = "/authz/role",
1876 errorCodes = {404,406},
1877 text = { "Add Description Data to a Role" }
1881 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1882 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1883 final ServiceValidator v = new ServiceValidator();
1884 if (v.role(rd).err()) {
1885 return Result.err(Status.ERR_BadData,v.errs());
1887 if (v.nullOrBlank("description", rd.value.description).err()) {
1888 return Result.err(Status.ERR_BadData,v.errs());
1891 final RoleDAO.Data role = rd.value;
1892 if (ques.roleDAO().read(trans, role.ns, role.name).notOKorIsEmpty()) {
1893 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1896 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1897 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1900 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1901 if (nsr.notOKorIsEmpty()) {
1902 return Result.err(nsr);
1905 Result<Void> rdr = ques.roleDAO().addDescription(trans, role.ns, role.name, role.description);
1909 return Result.err(rdr);
1916 path = "/authz/role/perm",
1919 errorCodes = {403,404,406,409},
1920 text = { "Grant a Permission to a Role",
1921 "Permission consists of:",
1922 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1923 + "is being protected</li>",
1924 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1925 + " instance of the type</li>",
1926 "<li>action - what kind of action is allowed</li></ul>",
1927 "Note: instance and action can be an *",
1928 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1929 " ID is allowed to create. It will then grant",
1930 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1935 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1936 // Translate Request into Perm and Role Objects
1937 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1938 if (rpd.notOKorIsEmpty()) {
1939 return Result.err(rpd);
1941 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1942 if (rrd.notOKorIsEmpty()) {
1943 return Result.err(rrd);
1946 // Validate Role and Perm values
1947 final ServiceValidator v = new ServiceValidator();
1948 if (v.perm(rpd.value)
1951 return Result.err(Status.ERR_BadData,v.errs());
1954 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().read(trans, rrd.value.ns, rrd.value.name);
1955 if (rlrd.notOKorIsEmpty()) {
1956 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1959 // Check Status of Data in DB (does it exist)
1960 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, rpd.value.ns,
1961 rpd.value.type, rpd.value.instance, rpd.value.action);
1962 PermDAO.Data createPerm = null; // if not null, create first
1963 if (rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1964 if (trans.requested(force)) {
1965 // Remove roles from perm data object so we just create the perm here
1966 createPerm = rpd.value;
1967 createPerm.roles.clear();
1969 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1970 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1973 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1974 return Result.err(Status.ERR_ConflictAlreadyExists,
1975 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1976 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1977 rrd.value.ns,rrd.value.name
1983 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1986 public String get() {
1987 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1988 " to Role [" + rrd.value.fullName() + "]";
1992 private Result<NsDAO.Data> nsd;
1994 public Result<?> mayChange() {
1996 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1998 trans.requested(REQD_TYPE.future,true);
2004 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rpd.value.ns);
2005 if (nsr.notOKorIsEmpty()) {
2006 return Result.err(nsr);
2010 Result<String> rfc = func.createFuture(trans,fd.value,
2011 rpd.value.fullPerm(),
2016 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2022 return Result.err(rfc);
2024 case Status.ACC_Now:
2025 Result<Void> rv = null;
2026 if (createPerm!=null) {// has been validated for creating
2027 rv = func.createPerm(trans, createPerm, false);
2029 if (rv==null || rv.isOK()) {
2030 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
2034 return Result.err(fd);
2040 * Delete Perms from Roles (UnGrant)
2042 * @param roleFullName
2047 path = "/authz/role/:role/perm",
2048 params = {"role|string|true"},
2050 errorCodes = {404,406},
2051 text = { "Ungrant a permission from Role :role" }
2055 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
2056 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
2057 if (updt.notOKorIsEmpty()) {
2058 return Result.err(updt);
2060 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
2061 if (rrd.notOKorIsEmpty()) {
2062 return Result.err(rrd);
2065 final ServiceValidator v = new ServiceValidator();
2066 if (v.nullOrBlank(updt.value)
2067 .nullOrBlank(rrd.value)
2069 return Result.err(Status.ERR_BadData,v.errs());
2072 return delPermFromRole(trans, updt.value,rrd.value, rreq);
2075 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
2076 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, pdd.ns, pdd.type,
2077 pdd.instance, pdd.action);
2079 if (rlpd.notOKorIsEmpty()) {
2080 return Result.err(Status.ERR_PermissionNotFound,
2081 "Permission [%s.%s|%s|%s] does not exist",
2082 pdd.ns,pdd.type,pdd.instance,pdd.action);
2085 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
2088 public String get() {
2089 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
2090 " from Role [" + rdd.fullName() + "]";
2094 private Result<NsDAO.Data> nsd;
2096 public Result<?> mayChange() {
2098 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2103 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pdd.ns);
2104 if (nsr.notOKorIsEmpty()) {
2105 return Result.err(nsr);
2109 Result<String> rfc = func.createFuture(trans,fd.value,
2116 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2122 return Result.err(rfc);
2124 case Status.ACC_Now:
2125 return func.delPermFromRole(trans, rdd, pdd, false);
2127 return Result.err(fd);
2134 path = "/authz/role/:role/perm/:type/:instance/:action",
2135 params = {"role|string|true",
2136 "perm type|string|true",
2137 "perm instance|string|true",
2138 "perm action|string|true"
2141 errorCodes = {404,406},
2142 text = { "Ungrant a single permission from Role :role with direct key" }
2146 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2147 Result<Data> rpns = ques.deriveNs(trans, type);
2148 if (rpns.notOKorIsEmpty()) {
2149 return Result.err(rpns);
2152 final Validator v = new ServiceValidator();
2154 .permType(rpns.value.name,rpns.value.parent)
2155 .permInstance(instance)
2158 return Result.err(Status.ERR_BadData,v.errs());
2161 Result<Data> rrns = ques.deriveNs(trans, role);
2162 if (rrns.notOKorIsEmpty()) {
2163 return Result.err(rrns);
2166 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, rrns.value.parent, rrns.value.name);
2167 if (rrd.notOKorIsEmpty()) {
2168 return Result.err(rrd);
2171 final Result<List<PermDAO.Data>> rpd = ques.permDAO().read(trans, rpns.value.parent, rpns.value.name, instance, action);
2172 if (rpd.notOKorIsEmpty()) {
2173 return Result.err(rpd);
2177 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2182 path = "/authz/role/:role",
2183 params = {"role|string|true"},
2185 errorCodes = {404,406},
2186 text = { "Delete the Role named :role"}
2190 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2191 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2192 if (rrdd.isOKhasData()) {
2193 final ServiceValidator v = new ServiceValidator();
2194 if (v.nullOrBlank(rrdd.value).err()) {
2195 return Result.err(Status.ERR_BadData,v.errs());
2197 return func.deleteRole(trans, rrdd.value, false, false);
2199 return Result.err(rrdd);
2205 path = "/authz/role",
2208 errorCodes = { 404,406 },
2209 text = { "Delete the Role referenced by RoleKey",
2210 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2211 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2212 "as a query parameter.",
2213 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2217 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2218 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2219 final ServiceValidator v = new ServiceValidator();
2221 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2223 if (v.nullOrBlank(rd.value).err()) {
2224 return Result.err(Status.ERR_BadData,v.errs());
2226 final RoleDAO.Data role = rd.value;
2227 if (ques.roleDAO().read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2228 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2231 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2232 () -> "Delete Role [" + role.fullName() + ']'
2233 + " and all attached user roles",
2235 private Result<NsDAO.Data> nsd;
2237 public Result<?> mayChange() {
2239 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2247 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
2248 if (nsr.notOKorIsEmpty()) {
2249 return Result.err(nsr);
2252 Result<String> rfc = func.createFuture(trans, fd.value,
2253 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2255 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2259 return Result.err(rfc);
2261 case Status.ACC_Now:
2262 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2264 return Result.err(fd);
2269 /***********************************
2271 ***********************************/
2272 private class MayCreateCred implements MayChange {
2273 private Result<NsDAO.Data> nsd;
2274 private AuthzTrans trans;
2275 private CredDAO.Data cred;
2276 private Executor exec;
2278 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2285 public Result<?> mayChange() {
2287 nsd = ques.validNSOfDomain(trans, cred.id);
2289 // is Ns of CredID valid?
2293 if (trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2296 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2297 if (rmc.isOKhasData()) {
2301 } catch (Exception e) {
2302 trans.warn().log(e);
2305 trans.warn().log(nsd.errorString());
2307 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2311 private class MayChangeCred implements MayChange {
2312 private static final String EXTEND = "extend";
2313 private static final String RESET = "reset";
2314 private static final String DELETE = "delete";
2315 private Result<NsDAO.Data> nsd;
2316 private AuthzTrans trans;
2317 private CredDAO.Data cred;
2318 private String action;
2319 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred, String action) {
2322 this.action = action;
2326 public Result<?> mayChange() {
2327 // User can change himself (but not create)
2329 nsd = ques.validNSOfDomain(trans, cred.id);
2331 // Get the Namespace
2333 String ns = nsd.value.name;
2334 String user = trans.user();
2336 String temp[] = Split.split('.',ns);
2337 switch(temp.length) {
2339 company = Defaults.AAF_NS;
2345 company = temp[0] + '.' + temp[1];
2350 if(ques.isOwner(trans, user,ns) ||
2351 ques.isAdmin(trans, user,ns) ||
2352 ques.isGranted(trans, user, ROOT_NS,"password",company,DELETE)) {
2358 if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,action)) {
2364 return Result.err(Status.ERR_Denied,"%s is not allowed to %s %s in %s",trans.user(),action,cred.id,cred.ns);
2368 private final long DAY_IN_MILLIS = 24*3600*1000L;
2372 path = "/authn/cred",
2375 errorCodes = {403,404,406,409},
2376 text = { "A credential consists of:",
2377 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2378 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2379 "AB1234@myapp.att.com</li>",
2380 "<li>password - Company Policy Compliant Password</li></ul>",
2381 "Note: AAF does support multiple credentials with the same ID.",
2382 "Check with your organization if you have this implemented."
2386 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2387 final String cmdDescription = ("Create User Credential");
2388 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2391 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2392 if (rcred.isOKhasData()) {
2393 rcred = ques.userCredSetup(trans, rcred.value);
2395 final ServiceValidator v = new ServiceValidator();
2397 if (v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2398 return Result.err(Status.ERR_BadData,v.errs());
2402 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2403 Identity mechID = null;
2404 Organization org = trans.org();
2406 mechID = org.getIdentity(trans, rcred.value.id);
2407 } catch (Exception e1) {
2408 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2410 if (mechID==null || !mechID.isFound()) {
2411 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2414 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2415 if (nsr.notOKorIsEmpty()) {
2416 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2420 boolean firstID = false;
2423 CassExecutor exec = new CassExecutor(trans, func);
2424 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2425 if (rlcd.isOKhasData()) {
2426 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2427 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2430 for (CredDAO.Data curr : rlcd.value) {
2431 // May not use the same password in the list
2432 // Note: ASPR specifies character differences, but we don't actually store the
2433 // password to validate char differences.
2435 // byte[] rawCred = rcred.value.type==CredDAO.RAW?null:; return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists");
2436 if(rcred.value.type==CredDAO.FQI ) {
2437 if(curr.type==CredDAO.FQI) {
2438 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists");
2442 rb = ques.userCredCheck(trans, curr, rcred.value.cred!=null?rcred.value.cred.array():null);
2444 return Result.err(rb);
2445 } else if (rb.value){
2446 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2447 } else if(Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires))
2448 && curr.type==rcred.value.type
2450 // Allow if expiring differential is greater than 1 day (for TEMP)
2451 // Unless expiring in 1 day
2452 if(System.currentTimeMillis() - rcred.value.expires.getTime() > TimeUnit.DAYS.toMillis(1)) {
2453 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists");
2460 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2461 String theMechID = rcred.value.id;
2462 Boolean otherMechIDs = false;
2463 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2464 for (CredDAO.Data cd : ques.credDAO().readNS(trans,nsr.value.get(0).name).value) {
2465 if (!cd.id.equals(theMechID)) {
2466 otherMechIDs = true;
2471 // We can say "ID does not exist" here
2472 if ((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2473 return Result.err(Status.ERR_Denied, reason);
2476 } catch (Exception e) {
2477 return Result.err(e);
2481 mc = new MayCreateCred(trans, rcred.value, exec);
2483 final CredDAO.Data cdd = rcred.value;
2484 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2487 public String get() {
2488 return cmdDescription + " [" +
2491 + cdd.expires + ']';
2498 Result<String> rfc = func.createFuture(trans, fd.value,
2499 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2500 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2502 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2504 Integer.toString(rcred.value.type),
2505 rcred.value.expires.toString());
2507 return Result.err(rfc);
2509 case Status.ACC_Now:
2512 // OK, it's a first ID, and not by NS Owner
2513 String user = trans.user();
2514 if(!ques.isOwner(trans,user,cdd.ns)) {
2515 // Admins are not allowed to set first Cred, but Org has already
2516 // said entity MAY create, typically by Permission
2517 // We can't know which reason they are allowed here, so we
2518 // have to assume that any with Special Permission would not be
2520 String domain = org.supportedDomain(user);
2521 if((domain!=null && !ques.isGranted(trans, user, ROOT_NS, "mechid", domain, Question.CREATE)) &&
2522 ques.isAdmin(trans, user, cdd.ns)) {
2523 return Result.err(Result.ERR_Denied,
2524 "Only Owners may create first passwords in their Namespace. Admins may modify after one exists" );
2526 // Allow IDs that AREN'T part of NS with Org Onboarding Permission (see Org object) to create Temp Passwords.
2527 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2531 } catch (Exception e) {
2532 trans.error().log(e, "While setting expiration to TempPassword");
2535 Result<?>udr = ques.credDAO().create(trans, rcred.value);
2539 return Result.err(udr);
2541 return Result.err(fd);
2545 return Result.err(rcred);
2554 path = "/authn/creds/ns/:ns",
2555 params = {"ns|string|true"},
2557 errorCodes = {403,404,406},
2558 text = { "Return all IDs in Namespace :ns"
2562 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2563 final Validator v = new ServiceValidator();
2564 if (v.ns(ns).err()) {
2565 return Result.err(Status.ERR_BadData,v.errs());
2568 // check if user is allowed to view NS
2569 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2571 return Result.err(rnd);
2573 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2575 return Result.err(rnd);
2578 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2580 USERS users = mapper.newInstance(API.USERS);
2581 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readNS(trans, ns);
2584 if (!rlcd.isEmpty()) {
2585 return mapper.cred(rlcd.value, users);
2587 return Result.ok(users);
2589 return Result.err(rlcd);
2599 path = "/authn/creds/id/:ns",
2600 params = {"id|string|true"},
2602 errorCodes = {403,404,406},
2603 text = { "Return all IDs in for ID"
2604 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2608 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2609 final Validator v = new ServiceValidator();
2610 if (v.nullOrBlank("ID",id).err()) {
2611 return Result.err(Status.ERR_BadData,v.errs());
2614 String ns = Question.domain2ns(id);
2615 // check if user is allowed to view NS
2616 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2618 return Result.err(rnd);
2620 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2622 return Result.err(rnd);
2625 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2627 USERS users = mapper.newInstance(API.USERS);
2628 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, id);
2631 if (!rlcd.isEmpty()) {
2632 return mapper.cred(rlcd.value, users);
2634 return Result.ok(users);
2636 return Result.err(rlcd);
2646 path = "/authn/certs/id/:id",
2647 params = {"id|string|true"},
2649 errorCodes = {403,404,406},
2650 text = { "Return Cert Info for ID"
2654 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2655 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2657 CERTS certs = mapper.newInstance(API.CERTS);
2658 Result<List<CertDAO.Data>> rlcd = ques.certDAO().readID(trans, id);
2661 if (!rlcd.isEmpty()) {
2662 return mapper.cert(rlcd.value, certs);
2664 return Result.ok(certs);
2666 return Result.err(rlcd);
2676 path = "/authn/cred",
2679 errorCodes = {300,403,404,406},
2680 text = { "Reset a Credential Password. If multiple credentials exist for this",
2681 "ID, you will need to specify which entry you are resetting in the",
2682 "CredRequest object"
2686 public Result<Void> resetUserCred(final AuthzTrans trans, REQUEST from) {
2687 final String cmdDescription = "Update User Credential";
2688 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2690 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2691 if (rcred.isOKhasData()) {
2692 rcred = ques.userCredSetup(trans, rcred.value);
2694 final ServiceValidator v = new ServiceValidator();
2696 if (v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2697 return Result.err(Status.ERR_BadData,v.errs());
2699 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2700 if (rlcd.notOKorIsEmpty()) {
2701 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2704 MayChange mc = new MayChangeCred(trans, rcred.value,MayChangeCred.RESET);
2705 Result<?> rmc = mc.mayChange();
2707 return Result.err(rmc);
2710 List<CredDAO.Data> lcdd = filterList(rlcd.value,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
2712 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, lcdd, MayChangeCred.RESET);
2714 return Result.err(ri);
2716 int entry = ri.value;
2719 final CredDAO.Data cred = rcred.value;
2721 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2724 public String get() {
2725 return cmdDescription + " [" +
2728 + cred.expires + ']';
2733 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2734 if (nsr.notOKorIsEmpty()) {
2735 return Result.err(nsr);
2740 Result<String> rfc = func.createFuture(trans, fd.value,
2741 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2742 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2744 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2746 Integer.toString(rcred.value.type),
2747 rcred.value.expires.toString());
2749 return Result.err(rfc);
2751 case Status.ACC_Now:
2752 Result<?>udr = null;
2753 // If we are Resetting Password on behalf of someone else (am not the Admin)
2754 // use TempPassword Expiration time.
2756 if (ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2757 exp = Expiration.Password;
2759 exp = Expiration.TempPassword;
2762 Organization org = trans.org();
2763 CredDAO.Data current = rlcd.value.get(entry);
2764 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2765 if (current.expires.equals(rcred.value.expires)
2766 && rlcd.value.get(entry).type==rcred.value.type) {
2767 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2768 gc = Chrono.firstMomentOfDay(gc);
2769 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2770 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2772 rcred.value.expires = org.expiration(null,exp).getTime();
2775 udr = ques.credDAO().create(trans, rcred.value);
2777 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2783 return Result.err(udr);
2785 return Result.err(fd);
2788 return Result.err(rcred);
2797 path = "/authn/cred/:days",
2798 params = {"days|string|true"},
2800 errorCodes = {300,403,404,406},
2801 text = { "Extend a Credential Expiration Date. The intention of this API is",
2802 "to avoid an outage in PROD due to a Credential expiring before it",
2803 "can be configured correctly. Measures are being put in place ",
2804 "so that this is not abused."
2808 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2809 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2811 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2812 Organization org = trans.org();
2813 final ServiceValidator v = new ServiceValidator();
2814 if (v.notOK(cred).err() ||
2815 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2816 v.user(org,cred.value.id).err()) {
2817 return Result.err(Status.ERR_BadData,v.errs());
2822 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2823 return Result.err(Status.ERR_Policy,reason);
2825 } catch (Exception e) {
2827 trans.error().log(e, msg="Could not contact Organization for User Validation");
2828 return Result.err(Status.ERR_Denied, msg);
2831 // Get the list of Cred Entries
2832 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2833 if (rlcd.notOKorIsEmpty()) {
2834 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2837 // Only Passwords can be extended
2838 List<CredDAO.Data> lcdd = filterList(rlcd.value,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
2840 //Need to do the "Pick Entry" mechanism
2842 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, lcdd, MayChangeCred.EXTEND);
2844 return Result.err(ri);
2847 CredDAO.Data found = lcdd.get(ri.value);
2848 CredDAO.Data cd = cred.value;
2849 // Copy over the cred
2851 cd.cred = found.cred;
2852 cd.other = found.other;
2853 cd.type = found.type;
2855 cd.notes = "Extended";
2857 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2858 if(cd.expires.before(found.expires)) {
2859 return Result.err(Result.ERR_BadData,String.format("Credential's expiration date is more than %s days in the future",days));
2862 cred = ques.credDAO().create(trans, cd);
2866 return Result.err(cred);
2874 path = "/authn/cred",
2877 errorCodes = {300,403,404,406},
2878 text = { "Delete a Credential. If multiple credentials exist for this",
2879 "ID, you will need to specify which entry you are deleting in the",
2880 "CredRequest object."
2884 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2885 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2886 final Validator v = new ServiceValidator();
2887 if (v.nullOrBlank("cred", cred.value.id).err()) {
2888 return Result.err(Status.ERR_BadData,v.errs());
2891 MayChange mc = new MayChangeCred(trans,cred.value,MayChangeCred.DELETE);
2892 Result<?> rmc = mc.mayChange();
2894 return Result.err(rmc);
2897 boolean doForce = trans.requested(force);
2898 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2899 if (rlcd.notOKorIsEmpty()) {
2900 // Empty Creds should not have user_roles.
2901 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2902 if (rlurd.isOKhasData()) {
2903 for (UserRoleDAO.Data data : rlurd.value) {
2904 ques.userRoleDAO().delete(trans, data, false);
2907 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2909 boolean isLastCred = rlcd.value.size()==1;
2912 CredRequest cr = (CredRequest)from;
2914 if(cr.getEntry()==null || "1".equals(cr.getEntry())) {
2917 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2922 if(cred.value.type==CredDAO.FQI) {
2924 for(CredDAO.Data cdd : rlcd.value) {
2926 if(cdd.type == CredDAO.FQI) {
2933 if (rlcd.value.size() > 1) {
2934 String inputOption = cr.getEntry();
2935 if (inputOption == null) {
2936 List<CredDAO.Data> list = filterList(rlcd.value,CredDAO.BASIC_AUTH,CredDAO.BASIC_AUTH_SHA256,CredDAO.CERT_SHA256_RSA);
2937 String message = selectCredFromList(list, MayChangeCred.DELETE);
2938 Object[] variables = buildVariables(list);
2939 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2942 if (inputOption.length()>5) { // should be a date
2943 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2944 for (CredDAO.Data cd : rlcd.value) {
2946 if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2952 entry = Integer.parseInt(inputOption) - 1;
2954 for (CredDAO.Data cd : rlcd.value) {
2955 if(cd.type!=CredDAO.BASIC_AUTH && cd.type!=CredDAO.BASIC_AUTH_SHA256 && cd.type!=CredDAO.CERT_SHA256_RSA) {
2963 } catch (NullPointerException e) {
2964 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2965 } catch (NumberFormatException e) {
2966 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2969 isLastCred = (entry==-1);
2973 if (entry < -1 || entry >= rlcd.value.size()) {
2974 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2980 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2981 () -> "Delete Credential [" +
2986 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
2987 if (nsr.notOKorIsEmpty()) {
2988 return Result.err(nsr);
2993 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2994 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2997 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2999 return Result.err(rfc);
3001 case Status.ACC_Now:
3002 Result<?>udr = null;
3003 if (!trans.requested(force)) {
3004 if (entry<0 || entry >= rlcd.value.size()) {
3005 if(cred.value.type==CredDAO.FQI) {
3006 return Result.err(Status.ERR_BadData,"FQI does not exist");
3008 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
3011 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
3013 for (CredDAO.Data curr : rlcd.value) {
3014 udr = ques.credDAO().delete(trans, curr, false);
3016 return Result.err(udr);
3021 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
3023 for (UserRoleDAO.Data data : rlurd.value) {
3024 ques.userRoleDAO().delete(trans, data, false);
3029 return Result.err(Result.ERR_NotFound,"No User Data found");
3034 return Result.err(udr);
3036 return Result.err(fd);
3042 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
3044 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd, String action) {
3046 if (lcd.size() > 1) {
3047 String inputOption = cr.getEntry();
3048 if (inputOption == null) {
3049 String message = selectCredFromList(lcd, action);
3050 Object[] variables = buildVariables(lcd);
3051 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
3053 if(MayChangeCred.EXTEND.equals(action)) {
3055 if(inputOption.length()>4) { //Tag is at least 12
3057 CredDAO.Data last = null;
3059 for(CredDAO.Data cdd : lcd) {
3060 if(inputOption.equals(cdd.tag)) {
3065 if(last.expires.before(cdd.expires)) {
3074 return Result.ok(lastIdx);
3076 return Result.err(Status.ERR_BadData, "User chose unknown Tag");
3079 entry = Integer.parseInt(inputOption) - 1;
3081 if (entry < 0 || entry >= lcd.size()) {
3082 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
3085 return Result.ok(entry);
3088 private List<CredDAO.Data> filterList(List<CredDAO.Data> orig, Integer ... types) {
3089 List<CredDAO.Data> rv = new ArrayList<>();
3090 for(CredDAO.Data cdd : orig) {
3092 for(int t : types) {
3099 Collections.sort(rv, (o1,o2) -> {
3100 if(o1.type==o2.type) {
3101 return o1.expires.compareTo(o2.expires);
3103 return o1.type.compareTo(o2.type);
3109 private String[] buildVariables(List<CredDAO.Data> value) {
3110 String [] vars = new String[value.size()];
3113 for (int i = 0; i < value.size(); i++) {
3115 vars[i] = cdd.id + TWO_SPACE + Define.getCredType(cdd.type) + TWO_SPACE + Chrono.niceUTCStamp(cdd.expires) + TWO_SPACE + cdd.tag;
3120 private String selectCredFromList(List<CredDAO.Data> value, String action) {
3121 StringBuilder errMessage = new StringBuilder();
3122 String userPrompt = MayChangeCred.DELETE.equals(action)?
3123 "Select which cred to delete (set force=true to delete all):":
3124 "Select which cred to " + action + ':';
3125 int numSpaces = value.get(0).id.length() - "Id".length();
3127 errMessage.append(userPrompt + '\n');
3128 errMessage.append(" ID");
3129 for (int i = 0; i < numSpaces; i++) {
3130 errMessage.append(' ');
3132 errMessage.append(" Type Expires Tag " + '\n');
3133 for (int i=0;i<value.size();++i) {
3134 errMessage.append(" %s\n");
3136 if(MayChangeCred.EXTEND.equals(action)) {
3137 errMessage.append("Run same command again with chosen entry or Tag as last parameter");
3139 errMessage.append("Run same command again with chosen entry as last parameter");
3141 return errMessage.toString();
3146 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
3147 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
3149 // Note: Mapper assigns RAW type
3150 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
3151 if (data.notOKorIsEmpty()) {
3152 return Result.err(data);
3154 CredDAO.Data cred = data.value; // of the Mapped Cred
3155 if (cred.cred==null) {
3156 return Result.err(Result.ERR_BadData,"No Password");
3158 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
3161 } catch (DAOException e) {
3162 trans.error().log(e,"Error looking up cred");
3163 return Result.err(Status.ERR_Denied,"Credential does not match");
3171 path = "/authn/validate",
3174 errorCodes = { 403 },
3175 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
3176 + "do more than BasicAuth as Credential types exp" }
3179 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
3180 //TODO how to make sure people don't use this in browsers? Do we care?
3181 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
3183 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
3184 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
3185 // Note: Only want to log problem, don't want to send back to end user
3189 trans.audit().log(rq.errorString());
3191 } catch (Exception e) {
3192 trans.warn().log(e);
3196 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
3201 path = "/authn/basicAuth",
3204 errorCodes = { 403 },
3205 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
3206 + "Use /authn/validate instead\n"
3207 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
3208 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
3209 + "security, and 403 if it does not." }
3211 private void basicAuth() {
3212 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
3215 /***********************************
3217 ***********************************/
3220 path = "/authz/userRole",
3223 errorCodes = {403,404,406,409},
3224 text = { "Create a UserRole relationship (add User to Role)",
3225 "A UserRole is an object Representation of membership of a Role for limited time.",
3226 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
3227 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
3228 "before Expirations expire. Namespace owners will be notified by email."
3232 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3233 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3235 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3236 if (urr.notOKorIsEmpty()) {
3237 return Result.err(urr);
3239 final UserRoleDAO.Data userRole = urr.value;
3241 final ServiceValidator v = new ServiceValidator();
3242 if (v.user_role(trans.user(),userRole).err() ||
3243 v.user(trans.org(), userRole.user).err()) {
3244 return Result.err(Status.ERR_BadData,v.errs());
3249 // Check if user can change first
3250 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3251 () -> "Add User [" + userRole.user + "] to Role [" +
3255 private Result<NsDAO.Data> nsd;
3257 public Result<?> mayChange() {
3258 if(urr.value.role.startsWith(urr.value.user)) {
3259 return Result.ok((NsDAO.Data)null);
3262 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3263 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3270 if(userRole.role.startsWith(userRole.user)) {
3271 userRole.ns=userRole.user;
3272 userRole.rname="user";
3275 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3277 return Result.err(nsr);
3284 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3285 userRole.user, ndd, FUTURE_OP.C);
3287 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3292 return Result.err(rfc);
3294 case Status.ACC_Now:
3295 return func.addUserRole(trans, userRole);
3297 return Result.err(fd);
3305 * getUserRolesByRole
3309 path = "/authz/userRoles/role/:role",
3310 params = {"role|string|true"},
3312 errorCodes = {404,406},
3313 text = { "List all Users that are attached to Role specified in :role",
3317 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3318 final Validator v = new ServiceValidator();
3319 if (v.nullOrBlank("Role",role).err()) {
3320 return Result.err(Status.ERR_BadData,v.errs());
3323 Result<RoleDAO.Data> rrdd;
3324 rrdd = RoleDAO.Data.decode(trans,ques,role);
3326 return Result.err(rrdd);
3328 // May Requester see result?
3329 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3331 return Result.err(ns);
3334 // boolean filter = true;
3335 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3338 // Get list of roles per user, then add to Roles as we go
3339 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3340 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3342 for (UserRoleDAO.Data data : rlurd.value) {
3347 @SuppressWarnings("unchecked")
3348 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3349 // Checked for permission
3350 mapper.userRoles(trans, userSet, users);
3351 return Result.ok(users);
3354 * getUserRolesByRole
3358 path = "/authz/userRoles/user/:user",
3359 params = {"role|string|true"},
3361 errorCodes = {404,406},
3362 text = { "List all UserRoles for :user",
3366 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3367 final Validator v = new ServiceValidator();
3368 if (v.nullOrBlank("User",user).err()) {
3369 return Result.err(Status.ERR_BadData,v.errs());
3372 // Get list of roles per user, then add to Roles as we go
3373 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
3374 if (rlurd.notOK()) {
3375 return Result.err(rlurd);
3380 * 2) is User's Supervisor
3381 * 3) Has special global access =read permission
3383 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3386 String callingUser = trans.getUserPrincipal().getName();
3387 NsDAO.Data ndd = new NsDAO.Data();
3389 if (user.equals(callingUser)) {
3392 Organization org = trans.org();
3394 Identity orgID = org.getIdentity(trans, user);
3395 Identity manager = orgID==null?null:orgID.responsibleTo();
3396 if (orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3398 } else if (ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3403 } catch (OrganizationException e) {
3409 List<UserRoleDAO.Data> content;
3411 content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos
3413 for (UserRoleDAO.Data data : rlurd.value) {
3415 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3422 content = rlurd.value;
3426 @SuppressWarnings("unchecked")
3427 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3428 // Checked for permission
3429 mapper.userRoles(trans, content, users);
3430 return Result.ok(users);
3438 path = "/authz/userRole/extend/:user/:role",
3439 params = { "user|string|true",
3443 errorCodes = {403,404,406},
3444 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3445 "Requestor must be allowed to modify the role"
3449 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3450 Organization org = trans.org();
3451 final ServiceValidator v = new ServiceValidator();
3452 if (v.user(org, user)
3455 return Result.err(Status.ERR_BadData,v.errs());
3458 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3460 return Result.err(rrdd);
3463 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3464 boolean mayNotChange;
3465 if ((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3466 return Result.err(rcr);
3469 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO().read(trans, user,role);
3471 return Result.err(rr);
3473 for (UserRoleDAO.Data userRole : rr.value) {
3474 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3475 FutureDAO.Data fto = new FutureDAO.Data();
3476 fto.target=UserRoleDAO.TABLE;
3477 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3478 GregorianCalendar now = new GregorianCalendar();
3479 fto.start = now.getTime();
3480 fto.expires = org.expiration(now, Expiration.Future).getTime();
3482 fto.construct = userRole.bytify();
3483 } catch (IOException e) {
3484 trans.error().log(e, "Error while bytifying UserRole for Future");
3485 return Result.err(e);
3488 Result<String> rfc = func.createFuture(trans, fto,
3489 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3491 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3495 return Result.err(rfc);
3498 return func.extendUserRole(trans, userRole, false);
3501 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3506 path = "/authz/userRole/:user/:role",
3507 params = { "user|string|true",
3511 errorCodes = {403,404,406},
3512 text = { "Remove Role :role from User :user."
3516 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3517 Validator val = new ServiceValidator();
3518 if (val.nullOrBlank("User", usr)
3519 .nullOrBlank("Role", role).err()) {
3520 return Result.err(Status.ERR_BadData, val.errs());
3523 boolean mayNotChange;
3524 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3526 return Result.err(rrdd);
3529 RoleDAO.Data rdd = rrdd.value;
3530 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3532 // Make sure we don't delete the last owner of valid NS
3533 if (rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3534 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3537 if (mayNotChange=rns.notOK()) {
3538 if (!trans.requested(future)) {
3539 return Result.err(rns);
3543 Result<List<UserRoleDAO.Data>> rulr;
3544 if ((rulr=ques.userRoleDAO().read(trans, usr, role)).notOKorIsEmpty()) {
3545 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3546 + "Assigned to the Role [ " + role + " ]");
3549 UserRoleDAO.Data userRole = rulr.value.get(0);
3550 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3551 FutureDAO.Data fto = new FutureDAO.Data();
3552 fto.target=UserRoleDAO.TABLE;
3553 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3554 GregorianCalendar now = new GregorianCalendar();
3555 fto.start = now.getTime();
3556 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3558 Result<String> rfc = func.createFuture(trans, fto,
3559 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3561 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3565 return Result.err(rfc);
3568 return ques.userRoleDAO().delete(trans, rulr.value.get(0), false);
3574 path = "/authz/userRole/:user/:role",
3575 params = {"user|string|true",
3576 "role|string|true"},
3578 errorCodes = {403,404,406},
3579 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3583 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3584 final Validator v = new ServiceValidator();
3585 if (v.role(role).nullOrBlank("User", user).err()) {
3586 return Result.err(Status.ERR_BadData,v.errs());
3589 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3590 // if (ns.notOK()) return Result.err(ns);
3592 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3593 // May calling user see by virtue of the Role
3594 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3596 return Result.err(rrdd);
3598 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3600 return Result.err(rnd);
3603 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3604 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readUserInRole(trans, user, role);
3606 for (UserRoleDAO.Data data : rlurd.value) {
3611 @SuppressWarnings("unchecked")
3612 USERS users = (USERS) mapper.newInstance(API.USERS);
3613 mapper.users(trans, userSet, users);
3614 return Result.ok(users);
3619 path = "/authz/users/role/:role",
3620 params = {"user|string|true",
3621 "role|string|true"},
3623 errorCodes = {403,404,406},
3624 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3628 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3629 final Validator v = new ServiceValidator();
3630 if (v.nullOrBlank("Role",role).err()) {
3631 return Result.err(Status.ERR_BadData,v.errs());
3634 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3635 // if (ns.notOK()) return Result.err(ns);
3637 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3638 // May calling user see by virtue of the Role
3639 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3641 return Result.err(rrdd);
3644 boolean contactOnly = false;
3645 // Allow the request of any valid user to find the contact of the NS (Owner)
3646 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3648 if (Question.OWNER.equals(rrdd.value.name)) {
3651 return Result.err(rnd);
3655 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3656 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3658 for (UserRoleDAO.Data data : rlurd.value) {
3659 if (contactOnly) { //scrub data
3660 // Can't change actual object, or will mess up the cache.
3661 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3663 scrub.rname = data.rname;
3664 scrub.role = data.role;
3665 scrub.user = data.user;
3673 @SuppressWarnings("unchecked")
3674 USERS users = (USERS) mapper.newInstance(API.USERS);
3675 mapper.users(trans, userSet, users);
3676 return Result.ok(users);
3680 * getUsersByPermission
3684 path = "/authz/users/perm/:type/:instance/:action",
3685 params = { "type|string|true",
3686 "instance|string|true",
3687 "action|string|true"
3690 errorCodes = {404,406},
3691 text = { "List all Users that have Permission specified by :type :instance :action",
3695 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3696 final Validator v = new ServiceValidator();
3697 if (v.nullOrBlank("Type",type)
3698 .nullOrBlank("Instance",instance)
3699 .nullOrBlank("Action",action)
3701 return Result.err(Status.ERR_BadData,v.errs());
3704 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3706 return Result.err(nss);
3709 Result<List<NsDAO.Data>> nsd = ques.nsDAO().read(trans, nss.value.ns);
3711 return Result.err(nsd);
3714 boolean allInstance = ASTERIX.equals(instance);
3715 boolean allAction = ASTERIX.equals(action);
3716 // Get list of roles per Permission,
3717 // Then loop through Roles to get Users
3718 // Note: Use Sets to avoid processing or responding with Duplicates
3719 Set<String> roleUsed = new HashSet<>();
3720 Set<UserRoleDAO.Data> userSet = new HashSet<>();
3722 if (!nss.isEmpty()) {
3723 Result<List<PermDAO.Data>> rlp = ques.permDAO().readByType(trans, nss.value.ns, nss.value.name);
3724 if (rlp.isOKhasData()) {
3725 for (PermDAO.Data pd : rlp.value) {
3726 if ((allInstance || pd.instance.equals(instance)) &&
3727 (allAction || pd.action.equals(action))) {
3728 if (ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3729 for (String role : pd.roles) {
3730 if (!roleUsed.contains(role)) { // avoid evaluating Role many times
3732 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role.replace('|', '.'));
3733 if (rlurd.isOKhasData()) {
3734 for (UserRoleDAO.Data urd : rlurd.value) {
3745 @SuppressWarnings("unchecked")
3746 USERS users = (USERS) mapper.newInstance(API.USERS);
3747 mapper.users(trans, userSet, users);
3748 return Result.ok(users);
3751 /***********************************
3753 ***********************************/
3755 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3756 final Validator v = new ServiceValidator();
3757 if (v.nullOrBlank("User",user).err()) {
3758 return Result.err(Status.ERR_BadData,v.errs());
3761 Result<NsDAO.Data> rnd;
3762 // Users may look at their own data
3763 if (trans.user().equals(user)) {
3764 // Users may look at their own data
3766 int at = user.indexOf('@');
3767 if (at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3768 NsDAO.Data nsd = new NsDAO.Data();
3769 nsd.name = Question.domain2ns(user);
3770 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3772 return Result.err(rnd);
3775 rnd = ques.validNSOfDomain(trans, user);
3777 return Result.err(rnd);
3780 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3782 return Result.err(rnd);
3786 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readByUser(trans, user, yyyymm);
3788 return Result.err(resp);
3790 return mapper.history(trans, resp.value,sort);
3794 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3795 final Validator v = new ServiceValidator();
3796 if (v.nullOrBlank("Role",role).err()) {
3797 return Result.err(Status.ERR_BadData,v.errs());
3800 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3802 return Result.err(rrdd);
3805 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3807 return Result.err(rnd);
3809 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, role, "role", yyyymm);
3811 return Result.err(resp);
3813 return mapper.history(trans, resp.value,sort);
3817 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3818 final Validator v = new ServiceValidator();
3819 if (v.nullOrBlank("Type",type)
3821 return Result.err(Status.ERR_BadData,v.errs());
3824 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3825 Result<List<HistoryDAO.Data>> resp;
3826 if(type.startsWith(trans.user())) {
3827 resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3829 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3831 return Result.err(rnd);
3833 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3835 return Result.err(rnd);
3837 resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3841 return Result.err(resp);
3843 return mapper.history(trans, resp.value,sort);
3847 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3848 final Validator v = new ServiceValidator();
3849 if (v.nullOrBlank("NS",ns).err()) {
3850 return Result.err(Status.ERR_BadData,v.errs());
3853 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3855 return Result.err(rnd);
3857 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3859 return Result.err(rnd);
3862 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, ns, "ns", yyyymm);
3864 return Result.err(resp);
3866 return mapper.history(trans, resp.value,sort);
3870 public Result<HISTORY> getHistoryBySubject(AuthzTrans trans, String subject, String target, int[] yyyymm, final int sort) {
3871 NsDAO.Data ndd = new NsDAO.Data();
3872 ndd.name = FQI.reverseDomain(subject);
3873 Result<Data> rnd = ques.mayUser(trans, trans.user(), ndd, Access.read);
3875 return Result.err(rnd);
3878 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, subject, target, yyyymm);
3880 return Result.err(resp);
3882 return mapper.history(trans, resp.value,sort);
3885 /***********************************
3887 ***********************************/
3889 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3890 return createOrUpdateDelegate(trans, base, Question.Access.create);
3894 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3895 return createOrUpdateDelegate(trans, base, Question.Access.write);
3899 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3900 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3901 final ServiceValidator v = new ServiceValidator();
3902 if (v.delegate(trans.org(),rd).err()) {
3903 return Result.err(Status.ERR_BadData,v.errs());
3906 final DelegateDAO.Data dd = rd.value;
3908 if(dd.user.contentEquals(dd.delegate) && !trans.requested(force)) {
3909 return Result.err(Status.ERR_InvalidDelegate,dd.user + " cannot delegate to self");
3912 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO().read(trans, dd);
3913 if (access==Access.create && ddr.isOKhasData()) {
3914 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3915 } else if (access!=Access.create && ddr.notOKorIsEmpty()) {
3916 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3918 Result<Void> rv = ques.mayUser(trans, dd, access);
3923 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3925 StringBuilder sb = new StringBuilder();
3926 sb.append(access.name());
3927 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3928 sb.append("Delegate ");
3929 sb.append(access==Access.create?"[":"to [");
3930 sb.append(rd.value.delegate);
3931 sb.append("] for [");
3932 sb.append(rd.value.user);
3934 return sb.toString();
3937 return Result.ok(); // Validate in code above
3942 Result<String> rfc = func.createFuture(trans, fd.value,
3943 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3945 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3948 return Result.err(rfc);
3950 case Status.ACC_Now:
3951 if (access==Access.create) {
3952 Result<DelegateDAO.Data> rdr = ques.delegateDAO().create(trans, dd);
3956 return Result.err(rdr);
3959 return ques.delegateDAO().update(trans, dd);
3962 return Result.err(fd);
3967 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3968 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3969 final Validator v = new ServiceValidator();
3970 if (v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3971 return Result.err(Status.ERR_BadData,v.errs());
3974 Result<List<DelegateDAO.Data>> ddl;
3975 if ((ddl=ques.delegateDAO().read(trans, rd.value)).notOKorIsEmpty()) {
3976 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3978 final DelegateDAO.Data dd = ddl.value.get(0);
3979 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3984 return ques.delegateDAO().delete(trans, dd, false);
3988 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3989 DelegateDAO.Data dd = new DelegateDAO.Data();
3990 final Validator v = new ServiceValidator();
3991 if (v.nullOrBlank("User", userName).err()) {
3992 return Result.err(Status.ERR_BadData,v.errs());
3995 Result<List<DelegateDAO.Data>> ddl;
3996 if ((ddl=ques.delegateDAO().read(trans, dd)).notOKorIsEmpty()) {
3997 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3999 dd = ddl.value.get(0);
4000 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
4005 return ques.delegateDAO().delete(trans, dd, false);
4009 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
4010 final Validator v = new ServiceValidator();
4011 if (v.nullOrBlank("User", user).err()) {
4012 return Result.err(Status.ERR_BadData,v.errs());
4015 DelegateDAO.Data ddd = new DelegateDAO.Data();
4017 ddd.delegate = null;
4018 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
4020 return Result.err(rv);
4023 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
4025 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().read(trans, user);
4027 if (dbDelgs.isOKhasData()) {
4028 return mapper.delegate(dbDelgs.value);
4030 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
4038 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
4039 final Validator v = new ServiceValidator();
4040 if (v.nullOrBlank("Delegate", delegate).err()) {
4041 return Result.err(Status.ERR_BadData,v.errs());
4044 DelegateDAO.Data ddd = new DelegateDAO.Data();
4045 ddd.user = delegate;
4046 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
4048 return Result.err(rv);
4051 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
4053 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().readByDelegate(trans, delegate);
4055 if (dbDelgs.isOKhasData()) {
4056 return mapper.delegate(dbDelgs.value);
4058 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
4065 /***********************************
4067 ***********************************/
4068 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
4070 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
4071 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
4073 return Result.err(rlad);
4075 int numApprs = rlad.value.size();
4077 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
4079 int numProcessed = 0;
4080 String user = trans.user();
4082 Result<List<ApprovalDAO.Data>> curr;
4083 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
4084 for (ApprovalDAO.Data updt : rlad.value) {
4085 if (updt.ticket!=null) {
4086 curr = ques.approvalDAO().readByTicket(trans, updt.ticket);
4087 if (curr.isOKhasData()) {
4088 final List<ApprovalDAO.Data> add = curr.value;
4089 // Store a Pre-Lookup
4090 apprByTicket = (trans1, noop) -> add;
4092 } else if (updt.id!=null) {
4093 curr = ques.approvalDAO().read(trans, updt);
4094 } else if (updt.approver!=null) {
4095 curr = ques.approvalDAO().readByApprover(trans, updt.approver);
4097 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
4100 if (curr.isOKhasData()) {
4101 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<>();
4102 Map<UUID, FutureDAO.Data> futureCache = new HashMap<>();
4103 FutureDAO.Data hasDeleted = new FutureDAO.Data();
4105 for (ApprovalDAO.Data cd : curr.value) {
4106 if ("pending".equals(cd.status)) {
4107 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
4109 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
4110 String delegator = cd.approver;
4111 if (updt.id!=null ||
4112 (updt.ticket!=null && user.equals(cd.approver)) ||
4113 (updt.ticket!=null && delegatedAction)) {
4114 if (updt.ticket.equals(cd.ticket)) {
4115 Changed ch = new Changed();
4116 cd.id = ch.changed(cd.id,updt.id);
4117 // cd.ticket = changed(cd.ticket,updt.ticket);
4118 cd.user = ch.changed(cd.user,updt.user);
4119 cd.approver = ch.changed(cd.approver,updt.approver);
4120 cd.type = ch.changed(cd.type,updt.type);
4121 cd.status = ch.changed(cd.status,updt.status);
4122 cd.memo = ch.changed(cd.memo,updt.memo);
4123 cd.operation = ch.changed(cd.operation,updt.operation);
4124 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
4125 // if (updt.status.equals("denied")) {
4126 // cd.last_notified = null;
4128 if (cd.ticket!=null) {
4129 FutureDAO.Data fdd = futureCache.get(cd.ticket);
4130 if (fdd==null) { // haven't processed ticket yet
4131 Result<FutureDAO.Data> rfdd = ques.futureDAO().readPrimKey(trans, cd.ticket);
4133 fdd = rfdd.value; // null is ok
4137 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
4139 if (fdd==hasDeleted) { // YES, by Object
4141 cd.status = "ticketDeleted";
4142 ch.hasChanged(true);
4144 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
4146 trans.info().printf("Approval Status %s is not actionable",cd.status);
4147 } else if (apprByTicket!=null) {
4148 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
4152 if (delegatedAction) {
4153 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
4155 futureCache.put(cd.ticket, hasDeleted);
4159 ch.hasChanged(true);
4160 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
4161 futureCache.put(cd.ticket, hasDeleted);
4166 trans.info().log(rv.toString());
4173 if (ch.hasChanged()) {
4174 ques.approvalDAO().update(trans, cd, true);
4183 if (numApprs==numProcessed) {
4186 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
4190 private static class Changed {
4191 private boolean hasChanged = false;
4193 public<T> T changed(T src, T proposed) {
4194 if (proposed==null || (src!=null && src.equals(proposed))) {
4201 public void hasChanged(boolean b) {
4205 public boolean hasChanged() {
4211 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
4212 final Validator v = new ServiceValidator();
4213 if (v.nullOrBlank("User", user).err()) {
4214 return Result.err(Status.ERR_BadData,v.errs());
4217 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByUser(trans, user);
4219 return mapper.approvals(rapd.value);
4221 return Result.err(rapd);
4226 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
4227 final Validator v = new ServiceValidator();
4228 if (v.nullOrBlank("Ticket", ticket).err()) {
4229 return Result.err(Status.ERR_BadData,v.errs());
4233 uuid = UUID.fromString(ticket);
4234 } catch (IllegalArgumentException e) {
4235 return Result.err(Status.ERR_BadData,e.getMessage());
4238 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByTicket(trans, uuid);
4240 return mapper.approvals(rapd.value);
4242 return Result.err(rapd);
4247 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
4248 final Validator v = new ServiceValidator();
4249 if (v.nullOrBlank("Approver", approver).err()) {
4250 return Result.err(Status.ERR_BadData,v.errs());
4253 List<ApprovalDAO.Data> listRapds = new ArrayList<>();
4255 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO().readByApprover(trans, approver);
4256 if (myRapd.notOK()) {
4257 return Result.err(myRapd);
4260 listRapds.addAll(myRapd.value);
4262 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO().readByDelegate(trans, approver);
4263 if (delegatedFor.isOK()) {
4264 for (DelegateDAO.Data dd : delegatedFor.value) {
4265 if (dd.expires.after(new Date())) {
4266 String delegator = dd.user;
4267 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByApprover(trans, delegator);
4269 for (ApprovalDAO.Data d : rapd.value) {
4270 if (!d.user.equals(trans.user())) {
4279 return mapper.approvals(listRapds);
4283 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4286 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4287 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4288 return ques.clearCache(trans,cname);
4290 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4291 trans.user(),ROOT_NS,CACHE,cname);
4295 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4298 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4299 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4300 Result<Void> v=null;
4301 for (int i: segment) {
4302 v=ques.cacheClear(trans,cname,i);
4308 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4309 trans.user(),ROOT_NS,CACHE,cname);
4313 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4316 public void dbReset(AuthzTrans trans) {
4317 ques.historyDAO().reportPerhapsReset(trans, null);