2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.auth.service;
24 import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.force;
25 import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.future;
26 import static org.onap.aaf.auth.layer.Result.OK;
27 import static org.onap.aaf.auth.rserv.HttpMethods.DELETE;
28 import static org.onap.aaf.auth.rserv.HttpMethods.GET;
29 import static org.onap.aaf.auth.rserv.HttpMethods.POST;
30 import static org.onap.aaf.auth.rserv.HttpMethods.PUT;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Date;
37 import java.util.GregorianCalendar;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
43 import java.util.TreeMap;
44 import java.util.UUID;
46 import javax.servlet.http.HttpServletRequest;
48 import org.onap.aaf.auth.common.Define;
49 import org.onap.aaf.auth.dao.DAOException;
50 import org.onap.aaf.auth.dao.cached.CachedPermDAO;
51 import org.onap.aaf.auth.dao.cached.CachedRoleDAO;
52 import org.onap.aaf.auth.dao.cached.CachedUserRoleDAO;
53 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
54 import org.onap.aaf.auth.dao.cass.CertDAO;
55 import org.onap.aaf.auth.dao.cass.CredDAO;
56 import org.onap.aaf.auth.dao.cass.DelegateDAO;
57 import org.onap.aaf.auth.dao.cass.FutureDAO;
58 import org.onap.aaf.auth.dao.cass.HistoryDAO;
59 import org.onap.aaf.auth.dao.cass.Namespace;
60 import org.onap.aaf.auth.dao.cass.NsDAO;
61 import org.onap.aaf.auth.dao.cass.NsDAO.Data;
62 import org.onap.aaf.auth.dao.cass.NsSplit;
63 import org.onap.aaf.auth.dao.cass.NsType;
64 import org.onap.aaf.auth.dao.cass.PermDAO;
65 import org.onap.aaf.auth.dao.cass.RoleDAO;
66 import org.onap.aaf.auth.dao.cass.Status;
67 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
68 import org.onap.aaf.auth.dao.hl.CassExecutor;
69 import org.onap.aaf.auth.dao.hl.Function;
70 import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP;
71 import org.onap.aaf.auth.dao.hl.Function.Lookup;
72 import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
73 import org.onap.aaf.auth.dao.hl.Question;
74 import org.onap.aaf.auth.dao.hl.Question.Access;
75 import org.onap.aaf.auth.env.AuthzTrans;
76 import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE;
77 import org.onap.aaf.auth.layer.Result;
78 import org.onap.aaf.auth.org.Executor;
79 import org.onap.aaf.auth.org.Organization;
80 import org.onap.aaf.auth.org.Organization.Expiration;
81 import org.onap.aaf.auth.org.Organization.Identity;
82 import org.onap.aaf.auth.org.Organization.Policy;
83 import org.onap.aaf.auth.org.OrganizationException;
84 import org.onap.aaf.auth.rserv.doc.ApiDoc;
85 import org.onap.aaf.auth.service.mapper.Mapper;
86 import org.onap.aaf.auth.service.mapper.Mapper.API;
87 import org.onap.aaf.auth.service.validation.ServiceValidator;
88 import org.onap.aaf.auth.validation.Validator;
89 import org.onap.aaf.cadi.aaf.Defaults;
90 import org.onap.aaf.cadi.principal.BasicPrincipal;
91 import org.onap.aaf.cadi.util.FQI;
92 import org.onap.aaf.misc.env.Env;
93 import org.onap.aaf.misc.env.TimeTaken;
94 import org.onap.aaf.misc.env.util.Chrono;
95 import org.onap.aaf.misc.env.util.Split;
97 import aaf.v2_0.CredRequest;
100 * AuthzCassServiceImpl implements AuthzCassService for
115 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
116 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
118 private static final String TWO_SPACE = " ";
119 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
121 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
123 private static final String ASTERIX = "*";
124 private static final String CACHE = "cache";
125 private static final String ROOT_NS = Define.ROOT_NS();
126 private static final String ROOT_COMPANY = Define.ROOT_COMPANY();
128 private final Question ques;
129 private final Function func;
131 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
132 this.ques = question;
133 func = new Function(trans, question);
134 this.mapper = mapper;
138 /***********************************
140 ***********************************/
143 * @throws DAOException
144 * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
151 errorCodes = { 403,404,406,409 },
152 text = { "Namespace consists of: ",
153 "<ul><li>name - What you want to call this Namespace</li>",
154 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
155 "regarding this Namespace. Companies have Policies as to who may take on ",
156 "this Responsibility. Separate multiple identities with commas</li>",
157 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
158 "including creating Roles, Permissions and Credentials. Separate multiple ",
159 "identities with commas</li></ul>",
160 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
161 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
162 "be an admin of com.myCompany or com"
166 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
167 final Result<Namespace> rnamespace = mapper.ns(trans, from);
168 final ServiceValidator v = new ServiceValidator();
169 if (v.ns(rnamespace).err()) {
170 return Result.err(Status.ERR_BadData,v.errs());
172 final Namespace namespace = rnamespace.value;
173 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
174 if (parentNs.notOK()) {
175 return Result.err(parentNs);
178 // Note: Data validate occurs in func.createNS
179 if (namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
180 return func.createNS(trans, namespace, false);
183 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
186 public String get() {
187 return "Create Namespace [" + namespace.name + ']';
191 private Result<NsDAO.Data> rnd;
193 public Result<?> mayChange() {
195 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
202 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
204 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
206 return Result.err(rfc);
209 return func.createNS(trans, namespace, false);
211 return Result.err(fd);
217 path = "/authz/ns/:ns/admin/:id",
218 params = { "ns|string|true",
222 errorCodes = { 403,404,406,409 },
223 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
224 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
227 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
228 return func.addUserRole(trans, id, ns,Question.ADMIN);
233 path = "/authz/ns/:ns/admin/:id",
234 params = { "ns|string|true",
238 errorCodes = { 403,404 },
239 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
240 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
243 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
244 return func.delAdmin(trans,ns,id);
249 path = "/authz/ns/:ns/responsible/:id",
250 params = { "ns|string|true",
254 errorCodes = { 403,404,406,409 },
255 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
256 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
259 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
260 return func.addUserRole(trans,id,ns,Question.OWNER);
265 path = "/authz/ns/:ns/responsible/:id",
266 params = { "ns|string|true",
270 errorCodes = { 403,404 },
271 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
272 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
273 "Note: A namespace must have at least 1 responsible party"
277 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
278 return func.delOwner(trans,ns,id);
282 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
286 path = "/authz/ns/:ns/attrib/:key/:value",
287 params = { "ns|string|true",
289 "value|string|true"},
291 errorCodes = { 403,404,406,409 },
293 "Create an attribute in the Namespace",
294 "You must be given direct permission for key by AAF"
298 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
299 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
302 final Validator v = new ServiceValidator();
303 if (v.ns(ns).err() ||
305 v.value(value).err()) {
306 return Result.err(Status.ERR_BadData,v.errs());
309 // Check if exists already
310 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
311 if (rlnsd.notOKorIsEmpty()) {
312 return Result.err(rlnsd);
314 NsDAO.Data nsd = rlnsd.value.get(0);
316 // Check for Existence
317 if (nsd.attrib.get(key)!=null) {
318 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
321 // Check if User may put
322 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
323 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
324 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
328 nsd.attrib.put(key, value);
329 ques.nsDAO().dao().attribAdd(trans,ns,key,value);
330 ques.nsDAO().invalidate(trans, nsd);
339 path = "/authz/ns/attrib/:key",
340 params = { "key|string|true" },
342 errorCodes = { 403,404 },
344 "Read Attributes for Namespace"
348 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
350 final Validator v = new ServiceValidator();
351 if (v.nullOrBlank("Key",key).err()) {
352 return Result.err(Status.ERR_BadData,v.errs());
356 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
357 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
358 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
361 Result<Set<String>> rsd = ques.nsDAO().dao().readNsByAttrib(trans, key);
363 return Result.err(rsd);
365 return mapper().keys(rsd.value);
371 path = "/authz/ns/:ns/attrib/:key/:value",
372 params = { "ns|string|true",
375 errorCodes = { 403,404 },
377 "Update Value on an existing attribute in the Namespace",
378 "You must be given direct permission for key by AAF"
382 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
383 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
386 final Validator v = new ServiceValidator();
387 if (v.ns(ns).err() ||
389 v.value(value).err()) {
390 return Result.err(Status.ERR_BadData,v.errs());
393 // Check if exists already (NS must exist)
394 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
395 if (rlnsd.notOKorIsEmpty()) {
396 return Result.err(rlnsd);
398 NsDAO.Data nsd = rlnsd.value.get(0);
400 // Check for Existence
401 if (nsd.attrib.get(key)==null) {
402 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
405 // Check if User may put
406 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
407 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
408 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
412 nsd.attrib.put(key, value);
413 ques.nsDAO().invalidate(trans, nsd);
414 return ques.nsDAO().update(trans,nsd);
423 path = "/authz/ns/:ns/attrib/:key",
424 params = { "ns|string|true",
427 errorCodes = { 403,404 },
429 "Delete an attribute in the Namespace",
430 "You must be given direct permission for key by AAF"
434 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
435 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
438 final Validator v = new ServiceValidator();
439 if (v.nullOrBlank("NS",ns).err() ||
440 v.nullOrBlank("Key",key).err()) {
441 return Result.err(Status.ERR_BadData,v.errs());
444 // Check if exists already
445 Result<List<Data>> rlnsd = ques.nsDAO().read(trans, ns);
446 if (rlnsd.notOKorIsEmpty()) {
447 return Result.err(rlnsd);
449 NsDAO.Data nsd = rlnsd.value.get(0);
451 // Check for Existence
452 if (nsd.attrib.get(key)==null) {
453 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
456 // Check if User may del
457 if (!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
458 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
462 nsd.attrib.remove(key);
463 ques.nsDAO().dao().attribRemove(trans,ns,key);
464 ques.nsDAO().invalidate(trans, nsd);
473 path = "/authz/nss/:id",
474 params = { "id|string|true" },
476 errorCodes = { 404,406 },
478 "Lists the Owner(s), Admin(s), Description, and Attributes of Namespace :id",
482 public Result<NSS> getNSbyName(AuthzTrans trans, String ns, boolean includeExpired) {
483 final Validator v = new ServiceValidator();
484 if (v.nullOrBlank("NS", ns).err()) {
485 return Result.err(Status.ERR_BadData,v.errs());
488 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, ns);
490 if (rlnd.isEmpty()) {
491 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
493 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
495 return Result.err(rnd);
499 Namespace namespace = new Namespace(rnd.value);
500 Result<List<String>> rd = func.getOwners(trans, namespace.name, includeExpired);
502 namespace.owner = rd.value;
504 rd = func.getAdmins(trans, namespace.name, includeExpired);
506 namespace.admin = rd.value;
509 NSS nss = mapper.newInstance(API.NSS);
510 return mapper.nss(trans, namespace, nss);
512 return Result.err(rlnd);
518 path = "/authz/nss/admin/:id",
519 params = { "id|string|true" },
521 errorCodes = { 403,404 },
522 text = { "Lists all Namespaces where Identity :id is an Admin",
523 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
527 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
528 final Validator v = new ServiceValidator();
529 if (v.nullOrBlank("User", user).err()) {
530 return Result.err(Status.ERR_BadData, v.errs());
533 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
535 return Result.err(rn);
538 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
540 NSS nss = mapper.newInstance(API.NSS);
541 // Note: "loadNamespace" already validates view of Namespace
542 return mapper.nss(trans, rn.value, nss);
547 path = "/authz/nss/either/:id",
548 params = { "id|string|true" },
550 errorCodes = { 403,404 },
551 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
552 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
556 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
557 final Validator v = new ServiceValidator();
558 if (v.nullOrBlank("User", user).err()) {
559 return Result.err(Status.ERR_BadData, v.errs());
562 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
564 return Result.err(rn);
567 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
569 NSS nss = mapper.newInstance(API.NSS);
570 // Note: "loadNamespace" already validates view of Namespace
571 return mapper.nss(trans, rn.value, nss);
574 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
575 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO().readByUser(trans, user);
576 if (urd.notOKorIsEmpty()) {
577 return Result.err(urd);
579 Map<String, Namespace> lm = new HashMap<>();
580 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<>();
581 for (UserRoleDAO.Data urdd : urd.value) {
583 if (endsWith==null || urdd.role.endsWith(endsWith)) {
584 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
585 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
587 Namespace namespace = lm.get(nsd.value.name);
588 if (namespace==null) {
589 namespace = new Namespace(nsd.value);
590 lm.put(namespace.name,namespace);
592 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
594 namespace.admin=rls.value;
597 rls = func.getOwners(trans, namespace.name, false);
599 namespace.owner=rls.value;
603 } else { // Shortened version. Only Namespace Info available from Role.
604 if (Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
605 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
606 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
608 Namespace namespace = lm.get(nsd.value.name);
609 if (namespace==null) {
611 namespace = other.remove(nsd.value.name);
613 if (namespace==null) {
614 namespace = new Namespace(nsd.value);
615 namespace.admin=new ArrayList<>();
616 namespace.owner=new ArrayList<>();
618 if (endsWith==null || urdd.role.endsWith(endsWith)) {
619 lm.put(namespace.name,namespace);
621 other.put(namespace.name,namespace);
624 if (Question.OWNER.equals(urdd.rname)) {
625 namespace.owner.add(urdd.user);
627 namespace.admin.add(urdd.user);
633 return Result.ok(lm.values());
638 path = "/authz/nss/responsible/:id",
639 params = { "id|string|true" },
641 errorCodes = { 403,404 },
642 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
643 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
647 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
648 final Validator v = new ServiceValidator();
649 if (v.nullOrBlank("User", user).err()) {
650 return Result.err(Status.ERR_BadData, v.errs());
652 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
654 return Result.err(rn);
657 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
659 NSS nss = mapper.newInstance(API.NSS);
660 // Note: "loadNamespace" prevalidates
661 return mapper.nss(trans, rn.value, nss);
666 path = "/authz/nss/children/:id",
667 params = { "id|string|true" },
669 errorCodes = { 403,404 },
670 text = { "Lists all Child Namespaces of Namespace :id",
671 "Note: This is not a cached read"
675 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
676 final Validator v = new ServiceValidator();
677 if (v.nullOrBlank("NS", parent).err()) {
678 return Result.err(Status.ERR_BadData,v.errs());
681 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
683 return Result.err(rnd);
685 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
687 return Result.err(rnd);
690 Set<Namespace> lm = new HashSet<>();
691 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().dao().getChildren(trans, parent);
693 if (rlnd.isEmpty()) {
694 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
696 for (NsDAO.Data ndd : rlnd.value) {
697 Namespace namespace = new Namespace(ndd);
698 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
700 namespace.admin=rls.value;
703 rls = func.getOwners(trans, namespace.name, false);
705 namespace.owner=rls.value;
710 NSS nss = mapper.newInstance(API.NSS);
711 return mapper.nss(trans,lm, nss);
713 return Result.err(rlnd);
723 errorCodes = { 403,404,406 },
724 text = { "Replace the Current Description of a Namespace with a new one"
728 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
729 final Result<Namespace> nsd = mapper.ns(trans, from);
730 final ServiceValidator v = new ServiceValidator();
731 if (v.ns(nsd).err()) {
732 return Result.err(Status.ERR_BadData,v.errs());
734 if (v.nullOrBlank("description", nsd.value.description).err()) {
735 return Result.err(Status.ERR_BadData,v.errs());
738 Namespace namespace = nsd.value;
739 Result<List<NsDAO.Data>> rlnd = ques.nsDAO().read(trans, namespace.name);
741 if (rlnd.notOKorIsEmpty()) {
742 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
745 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
746 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
749 Result<Void> rdr = ques.nsDAO().dao().addDescription(trans, namespace.name, namespace.description);
753 return Result.err(rdr);
759 * @throws DAOException
760 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
764 path = "/authz/ns/:ns",
765 params = { "ns|string|true" },
767 errorCodes = { 403,404,424 },
768 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
769 "are still credentials associated with them, but they can be deleted by setting ",
770 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
771 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
772 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
773 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
774 + "at or below Application Scope"
778 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
779 return func.deleteNS(trans, ns);
783 /***********************************
785 ***********************************/
789 * @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)
793 path = "/authz/perm",
796 errorCodes = {403,404,406,409},
797 text = { "Permission consists of:",
798 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
799 + "is being protected</li>",
800 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
801 + " instance of the type</li>",
802 "<li>action - what kind of action is allowed</li></ul>",
803 "Note: instance and action can be an *"
807 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
808 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
810 final ServiceValidator v = new ServiceValidator();
811 if (v.perm(newPd).err()) {
812 return Result.err(Status.ERR_BadData,v.errs());
815 // User Permission mechanism
816 if(newPd.value.ns.indexOf('@')>0) {
817 PermDAO.Data pdd = newPd.value;
818 if(trans.user().equals(newPd.value.ns)) {
819 CachedPermDAO permDAO = ques.permDAO();
820 Result<List<PermDAO.Data>> rlpdd = permDAO.read(trans, pdd);
822 return Result.err(rlpdd);
824 if(!rlpdd.isEmpty()) {
825 return Result.err(Result.ERR_ConflictAlreadyExists,"Permission already exists");
828 RoleDAO.Data rdd = new RoleDAO.Data();
832 pdd.roles(true).add(rdd.fullName());
833 Result<PermDAO.Data> rpdd = permDAO.create(trans, pdd);
835 return Result.err(rpdd);
838 CachedRoleDAO roleDAO = ques.roleDAO();
839 Result<List<RoleDAO.Data>> rlrdd = roleDAO.read(trans, rdd);
841 return Result.err(rlrdd);
843 if(!rlrdd.isEmpty()) {
844 rdd = rlrdd.value.get(0);
848 String eperm = pdd.encode();
849 rdd.perms(true).add(eperm);
850 Result<Void> rv = roleDAO.update(trans, rdd);
855 CachedUserRoleDAO urDAO = ques.userRoleDAO();
856 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
857 urdd.user = trans.user();
859 urdd.rname = rdd.name;
860 urdd.role = rdd.fullName();
861 Result<List<UserRoleDAO.Data>> rlurdd = urDAO.read(trans, urdd);
863 return Result.err(rlrdd);
864 } else if(rlurdd.isEmpty()) {
865 GregorianCalendar gc = trans.org().expiration(null, Expiration.UserInRole);
867 return Result.err(Result.ERR_Policy,"Organzation does not grant Expiration for UserRole");
869 urdd.expires = gc.getTime();
871 Result<UserRoleDAO.Data> rurdd = urDAO.create(trans, urdd);
872 return Result.err(rurdd);
876 return Result.err(Result.ERR_Security,"Only the User can create User Permissions");
879 // Does Perm Type exist as a Namespace?
880 if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
881 return Result.err(Status.ERR_ConflictAlreadyExists,
882 "Permission Type exists as a Namespace");
885 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
888 public String get() {
889 return "Create Permission [" +
890 newPd.value.fullType() + '|' +
891 newPd.value.instance + '|' +
892 newPd.value.action + ']';
896 private Result<NsDAO.Data> nsd;
898 public Result<?> mayChange() {
900 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
906 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
907 if (nsr.notOKorIsEmpty()) {
908 return Result.err(nsr);
912 Result<String> rfc = func.createFuture(trans,fd.value,
913 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
918 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
921 newPd.value.instance,
924 return Result.err(rfc);
927 return func.createPerm(trans, newPd.value, true);
929 return Result.err(fd);
936 path = "/authz/perms/:type",
937 params = {"type|string|true"},
939 errorCodes = { 404,406 },
940 text = { "List All Permissions that match the :type element of the key" }
943 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
944 final Validator v = new ServiceValidator();
945 if (v.nullOrBlank("PermType", permType).err()) {
946 return Result.err(Status.ERR_BadData,v.errs());
949 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
951 return Result.err(rlpd);
954 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
955 // Result<NsDAO.Data> r;
956 // if ((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
958 PERMS perms = mapper.newInstance(API.PERMS);
959 if (!rlpd.isEmpty()) {
960 // Note: Mapper will restrict what can be viewed
961 return mapper.perms(trans, rlpd.value, perms, true);
963 return Result.ok(perms);
968 path = "/authz/perms/:type/:instance/:action",
969 params = {"type|string|true",
970 "instance|string|true",
971 "action|string|true"},
973 errorCodes = { 404,406 },
974 text = { "List Permissions that match key; :type, :instance and :action" }
977 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
978 final Validator v = new ServiceValidator();
979 if (v.nullOrBlank("PermType", type).err()
980 || v.nullOrBlank("PermInstance", instance).err()
981 || v.nullOrBlank("PermAction", action).err()) {
982 return Result.err(Status.ERR_BadData,v.errs());
985 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
987 return Result.err(rlpd);
990 PERMS perms = mapper.newInstance(API.PERMS);
991 if (!rlpd.isEmpty()) {
992 // Note: Mapper will restrict what can be viewed
993 return mapper.perms(trans, rlpd.value, perms, true);
995 return Result.ok(perms);
1000 path = "/authz/perms/user/:user",
1001 params = {"user|string|true"},
1003 errorCodes = { 404,406 },
1004 text = { "List All Permissions that match user :user",
1005 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
1008 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
1009 final Validator v = new ServiceValidator();
1010 if (v.nullOrBlank("User", user).err()) {
1011 return Result.err(Status.ERR_BadData,v.errs());
1014 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,
1015 trans.requested(force));
1017 return Result.err(rlpd);
1020 PERMS perms = mapper.newInstance(API.PERMS);
1022 if (rlpd.isEmpty()) {
1023 return Result.ok(perms);
1025 // Note: Mapper will restrict what can be viewed
1026 // if user is the same as that which is looked up, no filtering is required
1027 return mapper.perms(trans, rlpd.value,
1029 !user.equals(trans.user()));
1034 path = "/authz/perms/user/:user/scope/:scope",
1035 params = {"user|string|true","scope|string|true"},
1037 errorCodes = { 404,406 },
1038 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
1039 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1040 "<p>'scope' must be expressed as NSs separated by ':'</p>"
1044 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
1045 final Validator v = new ServiceValidator();
1046 if (v.nullOrBlank("User", user).err()) {
1047 return Result.err(Status.ERR_BadData,v.errs());
1050 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
1052 return Result.err(rlpd);
1055 PERMS perms = mapper.newInstance(API.PERMS);
1057 if (rlpd.isEmpty()) {
1058 return Result.ok(perms);
1060 // Note: Mapper will restrict what can be viewed
1061 // if user is the same as that which is looked up, no filtering is required
1062 return mapper.perms(trans, rlpd.value,
1065 !user.equals(trans.user()));
1070 path = "/authz/perms/user/:user",
1071 params = {"user|string|true"},
1073 errorCodes = { 404,406 },
1074 text = { "List All Permissions that match user :user",
1075 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
1077 "Present Queries as one or more Permissions (see ContentType Links below for format).",
1079 "If the Caller is Granted this specific Permission, and the Permission is valid",
1080 " for the User, it will be included in response Permissions, along with",
1081 " all the normal permissions on the 'GET' version of this call. If it is not",
1082 " valid, or Caller does not have permission to see, it will be removed from the list",
1084 " *Note: This design allows you to make one call for all expected permissions",
1085 " The permission to be included MUST be:",
1086 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1088 " com.att.myns.access|:ns|write",
1089 " com.att.myns.access|:role:myrole|create",
1090 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1095 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1096 PERMS perms = _perms;
1097 final Validator v = new ServiceValidator();
1098 if (v.nullOrBlank("User", user).err()) {
1099 return Result.err(Status.ERR_BadData,v.errs());
1103 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.requested(force));
1105 return Result.err(rlpd);
1109 1) See if allowed to query
1110 2) See if User is allowed
1112 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1113 if (in.isOKhasData()) {
1114 List<PermDAO.Data> out = rlpd.value;
1116 for (PermDAO.Data pdd : in.value) {
1118 if ("access".equals(pdd.type)) {
1119 Access access = Access.valueOf(pdd.action);
1120 String[] mdkey = Split.splitTrim(':',pdd.instance);
1121 if (mdkey.length>1) {
1122 String type = mdkey[1];
1123 if ("role".equals(type)) {
1124 if (mdkey.length>2) {
1125 RoleDAO.Data rdd = new RoleDAO.Data();
1128 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1130 } else if ("perm".equals(type)) {
1131 if (mdkey.length>4) { // also need instance/action
1132 PermDAO.Data p = new PermDAO.Data();
1135 p.instance=mdkey[3];
1137 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1139 } else if ("ns".equals(type)) {
1140 NsDAO.Data ndd = new NsDAO.Data();
1142 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1152 perms = mapper.newInstance(API.PERMS);
1153 if (rlpd.isEmpty()) {
1154 return Result.ok(perms);
1156 // Note: Mapper will restrict what can be viewed
1157 // if user is the same as that which is looked up, no filtering is required
1158 return mapper.perms(trans, rlpd.value,
1160 !user.equals(trans.user()));
1165 path = "/authz/perms/role/:role",
1166 params = {"role|string|true"},
1168 errorCodes = { 404,406 },
1169 text = { "List All Permissions that are granted to :role" }
1172 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1173 final Validator v = new ServiceValidator();
1174 if (v.nullOrBlank("Role", role).err()) {
1175 return Result.err(Status.ERR_BadData,v.errs());
1178 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1180 return Result.err(rrdd);
1183 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1185 return Result.err(r);
1188 PERMS perms = mapper.newInstance(API.PERMS);
1190 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1191 if (rlpd.isOKhasData()) {
1192 // Note: Mapper will restrict what can be viewed
1193 return mapper.perms(trans, rlpd.value, perms, true);
1195 return Result.ok(perms);
1200 path = "/authz/perms/ns/:ns",
1201 params = {"ns|string|true"},
1203 errorCodes = { 404,406 },
1204 text = { "List All Permissions that are in Namespace :ns" }
1207 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1208 final Validator v = new ServiceValidator();
1209 if (v.nullOrBlank("NS", ns).err()) {
1210 return Result.err(Status.ERR_BadData,v.errs());
1213 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1215 return Result.err(rnd);
1218 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1220 return Result.err(rnd);
1223 Result<List<PermDAO.Data>> rlpd = ques.permDAO().readNS(trans, ns);
1225 return Result.err(rlpd);
1228 PERMS perms = mapper.newInstance(API.PERMS);
1229 if (!rlpd.isEmpty()) {
1230 // Note: Mapper will restrict what can be viewed
1231 return mapper.perms(trans, rlpd.value,perms, true);
1233 return Result.ok(perms);
1238 path = "/authz/perm/:type/:instance/:action",
1239 params = {"type|string|true",
1240 "instance|string|true",
1241 "action|string|true"},
1243 errorCodes = { 404,406, 409 },
1244 text = { "Rename the Permission referenced by :type :instance :action, and "
1245 + "rename (copy/delete) to the Permission described in PermRequest" }
1248 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1249 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1250 final ServiceValidator v = new ServiceValidator();
1251 if (v.perm(newPd).err()) {
1252 return Result.err(Status.ERR_BadData,v.errs());
1255 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1256 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1257 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1260 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1261 Result<List<PermDAO.Data>> origRlpd = ques.permDAO().read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1263 if (origRlpd.notOKorIsEmpty()) {
1264 return Result.err(Status.ERR_PermissionNotFound,
1265 "Permission [%s|%s|%s] does not exist",
1266 origType,origInstance,origAction);
1269 PermDAO.Data origPd = origRlpd.value.get(0);
1271 if (!origPd.ns.equals(newPd.value.ns)) {
1272 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1273 "<new type> must start with [" + origPd.ns + "]");
1276 if ( origPd.type.equals(newPd.value.type) &&
1277 origPd.action.equals(newPd.value.action) &&
1278 origPd.instance.equals(newPd.value.instance) ) {
1279 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1282 Set<String> origRoles = origPd.roles(false);
1283 if (!origRoles.isEmpty()) {
1284 Set<String> roles = newPd.value.roles(true);
1285 for (String role : origPd.roles) {
1290 newPd.value.description = origPd.description;
1292 Result<Void> rv = null;
1294 rv = func.createPerm(trans, newPd.value, false);
1296 rv = func.deletePerm(trans, origPd, true, false);
1303 path = "/authz/perm",
1306 errorCodes = { 404,406 },
1307 text = { "Add Description Data to Perm" }
1310 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1311 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1312 final ServiceValidator v = new ServiceValidator();
1313 if (v.perm(pd).err()) {
1314 return Result.err(Status.ERR_BadData,v.errs());
1316 if (v.nullOrBlank("description", pd.value.description).err()) {
1317 return Result.err(Status.ERR_BadData,v.errs());
1319 final PermDAO.Data perm = pd.value;
1320 if (ques.permDAO().read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1321 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1322 perm.ns,perm.type,perm.instance,perm.action);
1325 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1326 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1327 perm.ns,perm.type,perm.instance,perm.action);
1330 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pd.value.ns);
1331 if (nsr.notOKorIsEmpty()) {
1332 return Result.err(nsr);
1335 Result<Void> rdr = ques.permDAO().addDescription(trans, perm.ns, perm.type, perm.instance,
1336 perm.action, perm.description);
1340 return Result.err(rdr);
1347 path = "/authz/role/perm",
1350 errorCodes = {403,404,406,409},
1351 text = { "Set a permission's roles to roles given" }
1355 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1356 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1357 if (updt.notOKorIsEmpty()) {
1358 return Result.err(updt);
1361 final ServiceValidator v = new ServiceValidator();
1362 if (v.perm(updt).err()) {
1363 return Result.err(Status.ERR_BadData,v.errs());
1366 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1368 return Result.err(nsd);
1371 // Read full set to get CURRENT values
1372 Result<List<PermDAO.Data>> rcurr = ques.permDAO().read(trans,
1375 updt.value.instance,
1378 if (rcurr.notOKorIsEmpty()) {
1379 return Result.err(Status.ERR_PermissionNotFound,
1380 "Permission [%s.%s|%s|%s] does not exist",
1381 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1384 // Create a set of Update Roles, which are in Internal Format
1385 Set<String> updtRoles = new HashSet<>();
1386 Result<NsSplit> nss;
1387 for (String role : updt.value.roles(false)) {
1388 nss = ques.deriveNsSplit(trans, role);
1390 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1392 trans.error().log(nss.errorString());
1396 Result<Void> rv = null;
1398 for (PermDAO.Data curr : rcurr.value) {
1399 Set<String> currRoles = curr.roles(false);
1400 // must add roles to this perm, and add this perm to each role
1401 // in the update, but not in the current
1402 for (String role : updtRoles) {
1403 if (!currRoles.contains(role)) {
1404 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1405 if (key.isOKhasData()) {
1406 Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, key.value);
1407 if (rrd.isOKhasData()) {
1408 for (RoleDAO.Data r : rrd.value) {
1409 rv = func.addPermToRole(trans, r, curr, false);
1410 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1411 return Result.err(rv);
1415 return Result.err(rrd);
1420 // similarly, must delete roles from this perm, and delete this perm from each role
1421 // in the update, but not in the current
1422 for (String role : currRoles) {
1423 if (!updtRoles.contains(role)) {
1424 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1425 if (key.isOKhasData()) {
1426 Result<List<RoleDAO.Data>> rdd = ques.roleDAO().read(trans, key.value);
1427 if (rdd.isOKhasData()) {
1428 for (RoleDAO.Data r : rdd.value) {
1429 rv = func.delPermFromRole(trans, r, curr, true);
1430 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1431 return Result.err(rv);
1439 return rv==null?Result.ok():rv;
1444 path = "/authz/perm",
1447 errorCodes = { 404,406 },
1448 text = { "Delete the Permission referenced by PermKey.",
1449 "You cannot normally delete a permission which is still granted to roles,",
1450 "however the \"force\" property allows you to do just that. To do this: Add",
1451 "'force=true' as a query parameter.",
1452 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1455 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1456 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1458 return Result.err(pd);
1460 final ServiceValidator v = new ServiceValidator();
1461 if (v.nullOrBlank(pd.value).err()) {
1462 return Result.err(Status.ERR_BadData,v.errs());
1464 final PermDAO.Data perm = pd.value;
1465 if (ques.permDAO().read(trans, perm).notOKorIsEmpty()) {
1466 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1467 perm.ns,perm.type,perm.instance,perm.action );
1470 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1473 public String get() {
1474 return "Delete Permission [" + perm.fullPerm() + ']';
1478 private Result<NsDAO.Data> nsd;
1480 public Result<?> mayChange() {
1482 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1490 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, perm.ns);
1491 if (nsr.notOKorIsEmpty()) {
1492 return Result.err(nsr);
1495 Result<String> rfc = func.createFuture(trans, fd.value,
1496 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1498 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1500 return Result.err(rfc);
1502 case Status.ACC_Now:
1503 return func.deletePerm(trans,perm,trans.requested(force), false);
1505 return Result.err(fd);
1511 path = "/authz/perm/:name/:type/:action",
1512 params = {"type|string|true",
1513 "instance|string|true",
1514 "action|string|true"},
1516 errorCodes = { 404,406 },
1517 text = { "Delete the Permission referenced by :type :instance :action",
1518 "You cannot normally delete a permission which is still granted to roles,",
1519 "however the \"force\" property allows you to do just that. To do this: Add",
1520 "'force=true' as a query parameter",
1521 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1524 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1525 final Validator v = new ServiceValidator();
1526 if (v.nullOrBlank("Type",type)
1527 .nullOrBlank("Instance",instance)
1528 .nullOrBlank("Action",action)
1530 return Result.err(Status.ERR_BadData,v.errs());
1533 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1535 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1537 return Result.err(pd);
1541 /***********************************
1543 ***********************************/
1546 path = "/authz/role",
1549 errorCodes = {403,404,406,409},
1552 "Roles are part of Namespaces",
1554 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1555 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1556 "Restrictions on Role Names:",
1557 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1558 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1559 "<li>role names are Case Sensitive</li></ul>",
1560 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1561 "<ul><li>'What Job Function does this represent?'</li>",
1562 "<li>'Does this person perform this Job Function?'</li></ul>" }
1566 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1567 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1568 // Does Perm Type exist as a Namespace?
1569 if(rd.value.name.isEmpty() || ques.nsDAO().read(trans, rd.value.fullName()).isOKhasData()) {
1570 return Result.err(Status.ERR_ConflictAlreadyExists,
1571 "Role exists as a Namespace");
1573 final ServiceValidator v = new ServiceValidator();
1574 if (v.role(rd).err()) {
1575 return Result.err(Status.ERR_BadData,v.errs());
1577 final RoleDAO.Data role = rd.value;
1578 if (ques.roleDAO().read(trans, role.ns, role.name).isOKhasData()) {
1579 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1582 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1585 public String get() {
1586 return "Create Role [" +
1587 rd.value.fullName() +
1592 private Result<NsDAO.Data> nsd;
1594 public Result<?> mayChange() {
1596 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1602 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1603 if (nsr.notOKorIsEmpty()) {
1604 return Result.err(nsr);
1609 Result<String> rfc = func.createFuture(trans, fd.value,
1610 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1612 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1616 return Result.err(rfc);
1618 case Status.ACC_Now:
1619 Result<RoleDAO.Data> rdr = ques.roleDAO().create(trans, role);
1623 return Result.err(rdr);
1626 return Result.err(fd);
1631 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1635 path = "/authz/roles/:role",
1636 params = {"role|string|true"},
1638 errorCodes = {404,406},
1639 text = { "List Roles that match :role",
1640 "Note: You must have permission to see any given role"
1644 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1645 final Validator v = new ServiceValidator();
1646 if (v.nullOrBlank("Role", role).err()) {
1647 return Result.err(Status.ERR_BadData,v.errs());
1650 // Determine if User can ask this question
1651 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1652 if (rrdd.isOKhasData()) {
1653 Result<NsDAO.Data> r;
1654 if ((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1655 return Result.err(r);
1658 return Result.err(rrdd);
1662 int query = role.indexOf('?');
1663 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1665 // Note: Mapper will restrict what can be viewed
1666 ROLES roles = mapper.newInstance(API.ROLES);
1667 return mapper.roles(trans, rlrd.value, roles, true);
1669 return Result.err(rlrd);
1674 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1678 path = "/authz/roles/user/:name",
1679 params = {"name|string|true"},
1681 errorCodes = {404,406},
1682 text = { "List all Roles that match user :name",
1683 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1684 "Note: You must have permission to see any given role"
1689 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1690 final Validator v = new ServiceValidator();
1691 if (v.nullOrBlank("User", user).err()) {
1692 return Result.err(Status.ERR_BadData,v.errs());
1695 ROLES roles = mapper.newInstance(API.ROLES);
1696 // Get list of roles per user, then add to Roles as we go
1697 Result<List<RoleDAO.Data>> rlrd;
1698 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
1699 if (rlurd.isOKhasData()) {
1700 for (UserRoleDAO.Data urd : rlurd.value ) {
1701 rlrd = ques.roleDAO().read(trans, urd.ns,urd.rname);
1702 // Note: Mapper will restrict what can be viewed
1703 // if user is the same as that which is looked up, no filtering is required
1704 if (rlrd.isOKhasData()) {
1705 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1709 return Result.ok(roles);
1714 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1718 path = "/authz/roles/ns/:ns",
1719 params = {"ns|string|true"},
1721 errorCodes = {404,406},
1722 text = { "List all Roles for the Namespace :ns",
1723 "Note: You must have permission to see any given role"
1728 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1729 final Validator v = new ServiceValidator();
1730 if (v.nullOrBlank("NS", ns).err()) {
1731 return Result.err(Status.ERR_BadData,v.errs());
1734 // check if user is allowed to view NS
1735 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1737 return Result.err(rnsd);
1739 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1741 return Result.err(rnsd);
1744 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1746 ROLES roles = mapper.newInstance(API.ROLES);
1747 // Get list of roles per user, then add to Roles as we go
1748 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readNS(trans, ns);
1750 if (!rlrd.isEmpty()) {
1751 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1752 mapper.roles(trans,rlrd.value,roles,false);
1754 return Result.ok(roles);
1756 return Result.err(rlrd);
1765 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1769 path = "/authz/roles/name/:name",
1770 params = {"name|string|true"},
1772 errorCodes = {404,406},
1773 text = { "List all Roles for only the Name of Role (without Namespace)",
1774 "Note: You must have permission to see any given role"
1778 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1779 final Validator v = new ServiceValidator();
1780 if (v.nullOrBlank("Name", name).err()) {
1781 return Result.err(Status.ERR_BadData,v.errs());
1784 // User Mapper to make sure user is allowed to view NS
1786 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1788 ROLES roles = mapper.newInstance(API.ROLES);
1789 // Get list of roles per user, then add to Roles as we go
1790 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().readName(trans, name);
1792 if (!rlrd.isEmpty()) {
1793 // Note: Mapper will restrict what can be viewed
1794 mapper.roles(trans,rlrd.value,roles,true);
1796 return Result.ok(roles);
1798 return Result.err(rlrd);
1807 path = "/authz/roles/perm/:type/:instance/:action",
1808 params = {"type|string|true",
1809 "instance|string|true",
1810 "action|string|true"},
1812 errorCodes = {404,406},
1813 text = { "Find all Roles containing the given Permission." +
1814 "Permission consists of:",
1815 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1816 + "is being protected</li>",
1817 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1818 + " instance of the type</li>",
1819 "<li>action - what kind of action is allowed</li></ul>",
1820 "Notes: instance and action can be an *",
1821 " You must have permission to see any given role"
1826 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1827 final Validator v = new ServiceValidator();
1828 if (v.permType(type)
1829 .permInstance(instance)
1832 return Result.err(Status.ERR_BadData,v.errs());
1835 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1837 ROLES roles = mapper.newInstance(API.ROLES);
1838 // Get list of roles per user, then add to Roles as we go
1839 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1840 if (nsSplit.isOK()) {
1841 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1843 if ((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1844 return Result.err(res);
1847 Result<List<PermDAO.Data>> pdlr = ques.permDAO().read(trans, pdd);
1848 if (pdlr.isOK())for (PermDAO.Data pd : pdlr.value) {
1849 Result<List<RoleDAO.Data>> rlrd;
1850 for (String r : pd.roles) {
1851 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1853 rlrd = ques.roleDAO().read(trans, rs.value[0],rs.value[1]);
1854 // Note: Mapper will restrict what can be viewed
1855 if (rlrd.isOKhasData()) {
1856 mapper.roles(trans,rlrd.value,roles,true);
1862 return Result.ok(roles);
1870 path = "/authz/role",
1873 errorCodes = {404,406},
1874 text = { "Add Description Data to a Role" }
1878 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1879 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1880 final ServiceValidator v = new ServiceValidator();
1881 if (v.role(rd).err()) {
1882 return Result.err(Status.ERR_BadData,v.errs());
1884 if (v.nullOrBlank("description", rd.value.description).err()) {
1885 return Result.err(Status.ERR_BadData,v.errs());
1888 final RoleDAO.Data role = rd.value;
1889 if (ques.roleDAO().read(trans, role.ns, role.name).notOKorIsEmpty()) {
1890 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1893 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1894 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1897 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
1898 if (nsr.notOKorIsEmpty()) {
1899 return Result.err(nsr);
1902 Result<Void> rdr = ques.roleDAO().addDescription(trans, role.ns, role.name, role.description);
1906 return Result.err(rdr);
1913 path = "/authz/role/perm",
1916 errorCodes = {403,404,406,409},
1917 text = { "Grant a Permission to a Role",
1918 "Permission consists of:",
1919 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1920 + "is being protected</li>",
1921 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1922 + " instance of the type</li>",
1923 "<li>action - what kind of action is allowed</li></ul>",
1924 "Note: instance and action can be an *",
1925 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1926 " ID is allowed to create. It will then grant",
1927 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1932 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1933 // Translate Request into Perm and Role Objects
1934 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1935 if (rpd.notOKorIsEmpty()) {
1936 return Result.err(rpd);
1938 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1939 if (rrd.notOKorIsEmpty()) {
1940 return Result.err(rrd);
1943 // Validate Role and Perm values
1944 final ServiceValidator v = new ServiceValidator();
1945 if (v.perm(rpd.value)
1948 return Result.err(Status.ERR_BadData,v.errs());
1951 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO().read(trans, rrd.value.ns, rrd.value.name);
1952 if (rlrd.notOKorIsEmpty()) {
1953 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1956 // Check Status of Data in DB (does it exist)
1957 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, rpd.value.ns,
1958 rpd.value.type, rpd.value.instance, rpd.value.action);
1959 PermDAO.Data createPerm = null; // if not null, create first
1960 if (rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1961 if (trans.requested(force)) {
1962 // Remove roles from perm data object so we just create the perm here
1963 createPerm = rpd.value;
1964 createPerm.roles.clear();
1966 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1967 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1970 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1971 return Result.err(Status.ERR_ConflictAlreadyExists,
1972 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1973 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1974 rrd.value.ns,rrd.value.name
1980 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1983 public String get() {
1984 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1985 " to Role [" + rrd.value.fullName() + "]";
1989 private Result<NsDAO.Data> nsd;
1991 public Result<?> mayChange() {
1993 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1995 trans.requested(REQD_TYPE.future,true);
2001 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rpd.value.ns);
2002 if (nsr.notOKorIsEmpty()) {
2003 return Result.err(nsr);
2007 Result<String> rfc = func.createFuture(trans,fd.value,
2008 rpd.value.fullPerm(),
2013 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2019 return Result.err(rfc);
2021 case Status.ACC_Now:
2022 Result<Void> rv = null;
2023 if (createPerm!=null) {// has been validated for creating
2024 rv = func.createPerm(trans, createPerm, false);
2026 if (rv==null || rv.isOK()) {
2027 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
2031 return Result.err(fd);
2037 * Delete Perms from Roles (UnGrant)
2039 * @param roleFullName
2044 path = "/authz/role/:role/perm",
2045 params = {"role|string|true"},
2047 errorCodes = {404,406},
2048 text = { "Ungrant a permission from Role :role" }
2052 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
2053 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
2054 if (updt.notOKorIsEmpty()) {
2055 return Result.err(updt);
2057 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
2058 if (rrd.notOKorIsEmpty()) {
2059 return Result.err(rrd);
2062 final ServiceValidator v = new ServiceValidator();
2063 if (v.nullOrBlank(updt.value)
2064 .nullOrBlank(rrd.value)
2066 return Result.err(Status.ERR_BadData,v.errs());
2069 return delPermFromRole(trans, updt.value,rrd.value, rreq);
2072 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
2073 Result<List<PermDAO.Data>> rlpd = ques.permDAO().read(trans, pdd.ns, pdd.type,
2074 pdd.instance, pdd.action);
2076 if (rlpd.notOKorIsEmpty()) {
2077 return Result.err(Status.ERR_PermissionNotFound,
2078 "Permission [%s.%s|%s|%s] does not exist",
2079 pdd.ns,pdd.type,pdd.instance,pdd.action);
2082 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
2085 public String get() {
2086 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
2087 " from Role [" + rdd.fullName() + "]";
2091 private Result<NsDAO.Data> nsd;
2093 public Result<?> mayChange() {
2095 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2100 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, pdd.ns);
2101 if (nsr.notOKorIsEmpty()) {
2102 return Result.err(nsr);
2106 Result<String> rfc = func.createFuture(trans,fd.value,
2113 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2119 return Result.err(rfc);
2121 case Status.ACC_Now:
2122 return func.delPermFromRole(trans, rdd, pdd, false);
2124 return Result.err(fd);
2131 path = "/authz/role/:role/perm/:type/:instance/:action",
2132 params = {"role|string|true",
2133 "perm type|string|true",
2134 "perm instance|string|true",
2135 "perm action|string|true"
2138 errorCodes = {404,406},
2139 text = { "Ungrant a single permission from Role :role with direct key" }
2143 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2144 Result<Data> rpns = ques.deriveNs(trans, type);
2145 if (rpns.notOKorIsEmpty()) {
2146 return Result.err(rpns);
2149 final Validator v = new ServiceValidator();
2151 .permType(rpns.value.name,rpns.value.parent)
2152 .permInstance(instance)
2155 return Result.err(Status.ERR_BadData,v.errs());
2158 Result<Data> rrns = ques.deriveNs(trans, role);
2159 if (rrns.notOKorIsEmpty()) {
2160 return Result.err(rrns);
2163 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO().read(trans, rrns.value.parent, rrns.value.name);
2164 if (rrd.notOKorIsEmpty()) {
2165 return Result.err(rrd);
2168 final Result<List<PermDAO.Data>> rpd = ques.permDAO().read(trans, rpns.value.parent, rpns.value.name, instance, action);
2169 if (rpd.notOKorIsEmpty()) {
2170 return Result.err(rpd);
2174 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2179 path = "/authz/role/:role",
2180 params = {"role|string|true"},
2182 errorCodes = {404,406},
2183 text = { "Delete the Role named :role"}
2187 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2188 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2189 if (rrdd.isOKhasData()) {
2190 final ServiceValidator v = new ServiceValidator();
2191 if (v.nullOrBlank(rrdd.value).err()) {
2192 return Result.err(Status.ERR_BadData,v.errs());
2194 return func.deleteRole(trans, rrdd.value, false, false);
2196 return Result.err(rrdd);
2202 path = "/authz/role",
2205 errorCodes = { 404,406 },
2206 text = { "Delete the Role referenced by RoleKey",
2207 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2208 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2209 "as a query parameter.",
2210 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2214 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2215 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2216 final ServiceValidator v = new ServiceValidator();
2218 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2220 if (v.nullOrBlank(rd.value).err()) {
2221 return Result.err(Status.ERR_BadData,v.errs());
2223 final RoleDAO.Data role = rd.value;
2224 if (ques.roleDAO().read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2225 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2228 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2229 () -> "Delete Role [" + role.fullName() + ']'
2230 + " and all attached user roles",
2232 private Result<NsDAO.Data> nsd;
2234 public Result<?> mayChange() {
2236 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2244 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rd.value.ns);
2245 if (nsr.notOKorIsEmpty()) {
2246 return Result.err(nsr);
2249 Result<String> rfc = func.createFuture(trans, fd.value,
2250 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2252 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2256 return Result.err(rfc);
2258 case Status.ACC_Now:
2259 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2261 return Result.err(fd);
2266 /***********************************
2268 ***********************************/
2269 private class MayCreateCred implements MayChange {
2270 private Result<NsDAO.Data> nsd;
2271 private AuthzTrans trans;
2272 private CredDAO.Data cred;
2273 private Executor exec;
2275 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2282 public Result<?> mayChange() {
2284 nsd = ques.validNSOfDomain(trans, cred.id);
2286 // is Ns of CredID valid?
2290 if (trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2293 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2294 if (rmc.isOKhasData()) {
2298 } catch (Exception e) {
2299 trans.warn().log(e);
2302 trans.warn().log(nsd.errorString());
2304 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2308 private class MayChangeCred implements MayChange {
2309 private static final String EXTEND = "extend";
2310 private static final String RESET = "reset";
2311 private static final String DELETE = "delete";
2312 private Result<NsDAO.Data> nsd;
2313 private AuthzTrans trans;
2314 private CredDAO.Data cred;
2315 private String action;
2316 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred, String action) {
2319 this.action = action;
2323 public Result<?> mayChange() {
2324 // User can change himself (but not create)
2326 nsd = ques.validNSOfDomain(trans, cred.id);
2328 // Get the Namespace
2330 String ns = nsd.value.name;
2331 String user = trans.user();
2333 String temp[] = Split.split('.',ns);
2334 switch(temp.length) {
2336 company = Defaults.AAF_NS;
2342 company = temp[0] + '.' + temp[1];
2346 if(ques.isOwner(trans, user,ns) ||
2347 ques.isAdmin(trans, user,ns) ||
2348 ques.isGranted(trans, user, ROOT_NS,"password",company,DELETE)) {
2354 if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,action)) {
2360 return Result.err(Status.ERR_Denied,"%s is not allowed to %s %s in %s",trans.user(),action,cred.id,cred.ns);
2364 private final long DAY_IN_MILLIS = 24*3600*1000L;
2368 path = "/authn/cred",
2371 errorCodes = {403,404,406,409},
2372 text = { "A credential consists of:",
2373 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2374 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2375 "AB1234@myapp.att.com</li>",
2376 "<li>password - Company Policy Compliant Password</li></ul>",
2377 "Note: AAF does support multiple credentials with the same ID.",
2378 "Check with your organization if you have this implemented."
2382 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2383 final String cmdDescription = ("Create User Credential");
2384 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2387 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2388 if (rcred.isOKhasData()) {
2389 rcred = ques.userCredSetup(trans, rcred.value);
2391 final ServiceValidator v = new ServiceValidator();
2393 if (v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2394 return Result.err(Status.ERR_BadData,v.errs());
2398 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2399 Identity mechID = null;
2400 Organization org = trans.org();
2402 mechID = org.getIdentity(trans, rcred.value.id);
2403 } catch (Exception e1) {
2404 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2406 if (mechID==null || !mechID.isFound()) {
2407 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2410 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2411 if (nsr.notOKorIsEmpty()) {
2412 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2416 boolean firstID = false;
2419 CassExecutor exec = new CassExecutor(trans, func);
2420 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2421 if (rlcd.isOKhasData()) {
2422 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2423 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2426 for (CredDAO.Data curr : rlcd.value) {
2427 // May not use the same password in the list
2428 // Note: ASPR specifies character differences, but we don't actually store the
2429 // password to validate char differences.
2431 // byte[] rawCred = rcred.value.type==CredDAO.RAW?null:;
2433 rb = ques.userCredCheck(trans, curr, rcred.value.cred.array());
2435 return Result.err(rb);
2436 } else if (rb.value){
2437 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2438 } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
2439 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
2444 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2445 String theMechID = rcred.value.id;
2446 Boolean otherMechIDs = false;
2447 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2448 for (CredDAO.Data cd : ques.credDAO().readNS(trans,nsr.value.get(0).name).value) {
2449 if (!cd.id.equals(theMechID)) {
2450 otherMechIDs = true;
2455 // We can say "ID does not exist" here
2456 if ((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2457 return Result.err(Status.ERR_Denied, reason);
2460 } catch (Exception e) {
2461 return Result.err(e);
2465 mc = new MayCreateCred(trans, rcred.value, exec);
2467 final CredDAO.Data cdd = rcred.value;
2468 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2471 public String get() {
2472 return cmdDescription + " [" +
2475 + cdd.expires + ']';
2482 Result<String> rfc = func.createFuture(trans, fd.value,
2483 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2484 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2486 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2488 Integer.toString(rcred.value.type),
2489 rcred.value.expires.toString());
2491 return Result.err(rfc);
2493 case Status.ACC_Now:
2496 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
2497 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
2498 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
2499 // Note, we only do this on First time, because of possibility of
2500 // prematurely expiring a production id
2501 if (admins.isOKhasData() && !admins.value.contains(trans.user())) {
2502 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2505 } catch (Exception e) {
2506 trans.error().log(e, "While setting expiration to TempPassword");
2509 Result<?>udr = ques.credDAO().create(trans, rcred.value);
2513 return Result.err(udr);
2515 return Result.err(fd);
2519 return Result.err(rcred);
2528 path = "/authn/creds/ns/:ns",
2529 params = {"ns|string|true"},
2531 errorCodes = {403,404,406},
2532 text = { "Return all IDs in Namespace :ns"
2536 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2537 final Validator v = new ServiceValidator();
2538 if (v.ns(ns).err()) {
2539 return Result.err(Status.ERR_BadData,v.errs());
2542 // check if user is allowed to view NS
2543 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2545 return Result.err(rnd);
2547 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2549 return Result.err(rnd);
2552 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2554 USERS users = mapper.newInstance(API.USERS);
2555 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readNS(trans, ns);
2558 if (!rlcd.isEmpty()) {
2559 return mapper.cred(rlcd.value, users);
2561 return Result.ok(users);
2563 return Result.err(rlcd);
2573 path = "/authn/creds/id/:ns",
2574 params = {"id|string|true"},
2576 errorCodes = {403,404,406},
2577 text = { "Return all IDs in for ID"
2578 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2582 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2583 final Validator v = new ServiceValidator();
2584 if (v.nullOrBlank("ID",id).err()) {
2585 return Result.err(Status.ERR_BadData,v.errs());
2588 String ns = Question.domain2ns(id);
2589 // check if user is allowed to view NS
2590 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2592 return Result.err(rnd);
2594 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2596 return Result.err(rnd);
2599 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2601 USERS users = mapper.newInstance(API.USERS);
2602 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, id);
2605 if (!rlcd.isEmpty()) {
2606 return mapper.cred(rlcd.value, users);
2608 return Result.ok(users);
2610 return Result.err(rlcd);
2620 path = "/authn/certs/id/:id",
2621 params = {"id|string|true"},
2623 errorCodes = {403,404,406},
2624 text = { "Return Cert Info for ID"
2628 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2629 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2631 CERTS certs = mapper.newInstance(API.CERTS);
2632 Result<List<CertDAO.Data>> rlcd = ques.certDAO().readID(trans, id);
2635 if (!rlcd.isEmpty()) {
2636 return mapper.cert(rlcd.value, certs);
2638 return Result.ok(certs);
2640 return Result.err(rlcd);
2650 path = "/authn/cred",
2653 errorCodes = {300,403,404,406},
2654 text = { "Reset a Credential Password. If multiple credentials exist for this",
2655 "ID, you will need to specify which entry you are resetting in the",
2656 "CredRequest object"
2660 public Result<Void> resetUserCred(final AuthzTrans trans, REQUEST from) {
2661 final String cmdDescription = "Update User Credential";
2662 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2664 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2665 if (rcred.isOKhasData()) {
2666 rcred = ques.userCredSetup(trans, rcred.value);
2668 final ServiceValidator v = new ServiceValidator();
2670 if (v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2671 return Result.err(Status.ERR_BadData,v.errs());
2673 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, rcred.value.id);
2674 if (rlcd.notOKorIsEmpty()) {
2675 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2678 MayChange mc = new MayChangeCred(trans, rcred.value,MayChangeCred.RESET);
2679 Result<?> rmc = mc.mayChange();
2681 return Result.err(rmc);
2684 List<CredDAO.Data> lcdd = filterList(rlcd.value,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
2686 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, lcdd, MayChangeCred.RESET);
2688 return Result.err(ri);
2690 int entry = ri.value;
2693 final CredDAO.Data cred = rcred.value;
2695 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2698 public String get() {
2699 return cmdDescription + " [" +
2702 + cred.expires + ']';
2707 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, rcred.value.ns);
2708 if (nsr.notOKorIsEmpty()) {
2709 return Result.err(nsr);
2714 Result<String> rfc = func.createFuture(trans, fd.value,
2715 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2716 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2718 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2720 Integer.toString(rcred.value.type),
2721 rcred.value.expires.toString());
2723 return Result.err(rfc);
2725 case Status.ACC_Now:
2726 Result<?>udr = null;
2727 // If we are Resetting Password on behalf of someone else (am not the Admin)
2728 // use TempPassword Expiration time.
2730 if (ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2731 exp = Expiration.Password;
2733 exp = Expiration.TempPassword;
2736 Organization org = trans.org();
2737 CredDAO.Data current = rlcd.value.get(entry);
2738 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2739 if (current.expires.equals(rcred.value.expires)
2740 && rlcd.value.get(entry).type==rcred.value.type) {
2741 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2742 gc = Chrono.firstMomentOfDay(gc);
2743 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2744 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2746 rcred.value.expires = org.expiration(null,exp).getTime();
2749 udr = ques.credDAO().create(trans, rcred.value);
2751 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2757 return Result.err(udr);
2759 return Result.err(fd);
2762 return Result.err(rcred);
2771 path = "/authn/cred/:days",
2772 params = {"days|string|true"},
2774 errorCodes = {300,403,404,406},
2775 text = { "Extend a Credential Expiration Date. The intention of this API is",
2776 "to avoid an outage in PROD due to a Credential expiring before it",
2777 "can be configured correctly. Measures are being put in place ",
2778 "so that this is not abused."
2782 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2783 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2785 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2786 Organization org = trans.org();
2787 final ServiceValidator v = new ServiceValidator();
2788 if (v.notOK(cred).err() ||
2789 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2790 v.user(org,cred.value.id).err()) {
2791 return Result.err(Status.ERR_BadData,v.errs());
2796 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2797 return Result.err(Status.ERR_Policy,reason);
2799 } catch (Exception e) {
2801 trans.error().log(e, msg="Could not contact Organization for User Validation");
2802 return Result.err(Status.ERR_Denied, msg);
2805 // Get the list of Cred Entries
2806 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2807 if (rlcd.notOKorIsEmpty()) {
2808 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2811 // Only Passwords can be extended
2812 List<CredDAO.Data> lcdd = filterList(rlcd.value,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
2814 //Need to do the "Pick Entry" mechanism
2816 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, lcdd, "extend");
2818 return Result.err(ri);
2821 CredDAO.Data found = lcdd.get(ri.value);
2822 CredDAO.Data cd = cred.value;
2823 // Copy over the cred
2825 cd.cred = found.cred;
2826 cd.other = found.other;
2827 cd.type = found.type;
2829 cd.notes = "Extended";
2830 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2833 cred = ques.credDAO().create(trans, cd);
2837 return Result.err(cred);
2845 path = "/authn/cred",
2848 errorCodes = {300,403,404,406},
2849 text = { "Delete a Credential. If multiple credentials exist for this",
2850 "ID, you will need to specify which entry you are deleting in the",
2851 "CredRequest object."
2855 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2856 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2857 final Validator v = new ServiceValidator();
2858 if (v.nullOrBlank("cred", cred.value.id).err()) {
2859 return Result.err(Status.ERR_BadData,v.errs());
2862 MayChange mc = new MayChangeCred(trans,cred.value,MayChangeCred.DELETE);
2863 Result<?> rmc = mc.mayChange();
2865 return Result.err(rmc);
2868 Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
2869 if (rlcd.notOKorIsEmpty()) {
2870 // Empty Creds should have no user_roles.
2871 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2873 for (UserRoleDAO.Data data : rlurd.value) {
2874 ques.userRoleDAO().delete(trans, data, false);
2877 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2879 boolean isLastCred = rlcd.value.size()==1;
2883 if (!trans.requested(force)) {
2884 if (rlcd.value.size() > 1) {
2885 CredRequest cr = (CredRequest)from;
2886 String inputOption = cr.getEntry();
2887 if (inputOption == null) {
2888 List<CredDAO.Data> list = filterList(rlcd.value,CredDAO.BASIC_AUTH,CredDAO.BASIC_AUTH_SHA256,CredDAO.CERT_SHA256_RSA);
2889 String message = selectCredFromList(list, MayChangeCred.DELETE);
2890 Object[] variables = buildVariables(list);
2891 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2894 if (inputOption.length()>5) { // should be a date
2895 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2897 for (CredDAO.Data cd : rlcd.value) {
2898 if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2904 entry = Integer.parseInt(inputOption) - 1;
2906 } catch (NullPointerException e) {
2907 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2908 } catch (NumberFormatException e) {
2909 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2912 isLastCred = (entry==-1)?true:false;
2916 if (entry < -1 || entry >= rlcd.value.size()) {
2917 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2921 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2922 () -> "Delete Credential [" +
2927 Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
2928 if (nsr.notOKorIsEmpty()) {
2929 return Result.err(nsr);
2934 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2935 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2938 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2940 return Result.err(rfc);
2942 case Status.ACC_Now:
2943 Result<?>udr = null;
2944 if (!trans.requested(force)) {
2945 if (entry<0 || entry >= rlcd.value.size()) {
2946 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
2948 udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
2950 for (CredDAO.Data curr : rlcd.value) {
2951 udr = ques.credDAO().delete(trans, curr, false);
2953 return Result.err(udr);
2958 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
2960 for (UserRoleDAO.Data data : rlurd.value) {
2961 ques.userRoleDAO().delete(trans, data, false);
2966 return Result.err(Result.ERR_NotFound,"No User Data found");
2971 return Result.err(udr);
2973 return Result.err(fd);
2979 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
2981 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd, String action) {
2983 if (lcd.size() > 1) {
2984 String inputOption = cr.getEntry();
2985 if (inputOption == null) {
2986 String message = selectCredFromList(lcd, action);
2987 Object[] variables = buildVariables(lcd);
2988 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2990 entry = Integer.parseInt(inputOption) - 1;
2992 if (entry < 0 || entry >= lcd.size()) {
2993 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2996 return Result.ok(entry);
2999 private List<CredDAO.Data> filterList(List<CredDAO.Data> orig, Integer ... types) {
3000 List<CredDAO.Data> rv = new ArrayList<>();
3001 for(CredDAO.Data cdd : orig) {
3003 for(int t : types) {
3013 private String[] buildVariables(List<CredDAO.Data> value) {
3014 // ensure credentials are sorted so we can fully automate Cred regression test
3015 Collections.sort(value, (cred1, cred2) ->
3016 cred1.type==cred2.type?cred2.expires.compareTo(cred1.expires):
3017 cred1.type<cred2.type?-1:1);
3018 String [] vars = new String[value.size()+1];
3021 for (int i = 0; i < value.size(); i++) {
3023 vars[i+1] = cdd.id + TWO_SPACE + cdd.type + TWO_SPACE + (cdd.type<10?TWO_SPACE:"")+ cdd.expires + TWO_SPACE + cdd.tag;
3028 private String selectCredFromList(List<CredDAO.Data> value, String action) {
3029 StringBuilder errMessage = new StringBuilder();
3030 String userPrompt = MayChangeCred.DELETE.equals(action)?
3031 "Select which cred to delete (set force=true to delete all):":
3032 "Select which cred to " + action + ':';
3033 int numSpaces = value.get(0).id.length() - "Id".length();
3035 errMessage.append(userPrompt + '\n');
3036 errMessage.append(" ID");
3037 for (int i = 0; i < numSpaces; i++) {
3038 errMessage.append(' ');
3040 errMessage.append(" Type Expires Tag " + '\n');
3041 for (int i=0;i<value.size();++i) {
3042 errMessage.append(" %s\n");
3044 errMessage.append("Run same command again with chosen entry as last parameter");
3046 return errMessage.toString();
3051 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
3052 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
3054 // Note: Mapper assigns RAW type
3055 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
3056 if (data.notOKorIsEmpty()) {
3057 return Result.err(data);
3059 CredDAO.Data cred = data.value; // of the Mapped Cred
3060 if (cred.cred==null) {
3061 return Result.err(Result.ERR_BadData,"No Password");
3063 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
3066 } catch (DAOException e) {
3067 trans.error().log(e,"Error looking up cred");
3068 return Result.err(Status.ERR_Denied,"Credential does not match");
3076 path = "/authn/validate",
3079 errorCodes = { 403 },
3080 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
3081 + "do more than BasicAuth as Credential types exp" }
3084 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
3085 //TODO how to make sure people don't use this in browsers? Do we care?
3086 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
3088 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
3089 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
3090 // Note: Only want to log problem, don't want to send back to end user
3094 trans.audit().log(rq.errorString());
3096 } catch (Exception e) {
3097 trans.warn().log(e);
3101 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
3106 path = "/authn/basicAuth",
3109 errorCodes = { 403 },
3110 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
3111 + "Use /authn/validate instead\n"
3112 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
3113 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
3114 + "security, and 403 if it does not." }
3116 private void basicAuth() {
3117 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
3120 /***********************************
3122 ***********************************/
3125 path = "/authz/userRole",
3128 errorCodes = {403,404,406,409},
3129 text = { "Create a UserRole relationship (add User to Role)",
3130 "A UserRole is an object Representation of membership of a Role for limited time.",
3131 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
3132 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
3133 "before Expirations expire. Namespace owners will be notified by email."
3137 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3138 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3140 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3141 if (urr.notOKorIsEmpty()) {
3142 return Result.err(urr);
3144 final UserRoleDAO.Data userRole = urr.value;
3146 final ServiceValidator v = new ServiceValidator();
3147 if (v.user_role(trans.user(),userRole).err() ||
3148 v.user(trans.org(), userRole.user).err()) {
3149 return Result.err(Status.ERR_BadData,v.errs());
3154 // Check if user can change first
3155 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3156 () -> "Add User [" + userRole.user + "] to Role [" +
3160 private Result<NsDAO.Data> nsd;
3162 public Result<?> mayChange() {
3163 if(urr.value.role.startsWith(urr.value.user)) {
3164 return Result.ok((NsDAO.Data)null);
3167 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3168 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3175 if(userRole.role.startsWith(userRole.user)) {
3176 userRole.ns=userRole.user;
3177 userRole.rname="user";
3180 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3182 return Result.err(nsr);
3189 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3190 userRole.user, ndd, FUTURE_OP.C);
3192 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3197 return Result.err(rfc);
3199 case Status.ACC_Now:
3200 return func.addUserRole(trans, userRole);
3202 return Result.err(fd);
3210 * getUserRolesByRole
3214 path = "/authz/userRoles/role/:role",
3215 params = {"role|string|true"},
3217 errorCodes = {404,406},
3218 text = { "List all Users that are attached to Role specified in :role",
3222 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3223 final Validator v = new ServiceValidator();
3224 if (v.nullOrBlank("Role",role).err()) {
3225 return Result.err(Status.ERR_BadData,v.errs());
3228 Result<RoleDAO.Data> rrdd;
3229 rrdd = RoleDAO.Data.decode(trans,ques,role);
3231 return Result.err(rrdd);
3233 // May Requester see result?
3234 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3236 return Result.err(ns);
3239 // boolean filter = true;
3240 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3243 // Get list of roles per user, then add to Roles as we go
3244 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3245 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3247 for (UserRoleDAO.Data data : rlurd.value) {
3252 @SuppressWarnings("unchecked")
3253 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3254 // Checked for permission
3255 mapper.userRoles(trans, userSet, users);
3256 return Result.ok(users);
3259 * getUserRolesByRole
3263 path = "/authz/userRoles/user/:user",
3264 params = {"role|string|true"},
3266 errorCodes = {404,406},
3267 text = { "List all UserRoles for :user",
3271 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3272 final Validator v = new ServiceValidator();
3273 if (v.nullOrBlank("User",user).err()) {
3274 return Result.err(Status.ERR_BadData,v.errs());
3277 // Get list of roles per user, then add to Roles as we go
3278 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, user);
3279 if (rlurd.notOK()) {
3280 return Result.err(rlurd);
3285 * 2) is User's Supervisor
3286 * 3) Has special global access =read permission
3288 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3291 String callingUser = trans.getUserPrincipal().getName();
3292 NsDAO.Data ndd = new NsDAO.Data();
3294 if (user.equals(callingUser)) {
3297 Organization org = trans.org();
3299 Identity orgID = org.getIdentity(trans, user);
3300 Identity manager = orgID==null?null:orgID.responsibleTo();
3301 if (orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3303 } else if (ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3308 } catch (OrganizationException e) {
3314 List<UserRoleDAO.Data> content;
3316 content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos
3318 for (UserRoleDAO.Data data : rlurd.value) {
3320 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3327 content = rlurd.value;
3331 @SuppressWarnings("unchecked")
3332 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3333 // Checked for permission
3334 mapper.userRoles(trans, content, users);
3335 return Result.ok(users);
3343 path = "/authz/userRole/extend/:user/:role",
3344 params = { "user|string|true",
3348 errorCodes = {403,404,406},
3349 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3350 "Requestor must be allowed to modify the role"
3354 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3355 Organization org = trans.org();
3356 final ServiceValidator v = new ServiceValidator();
3357 if (v.user(org, user)
3360 return Result.err(Status.ERR_BadData,v.errs());
3363 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3365 return Result.err(rrdd);
3368 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3369 boolean mayNotChange;
3370 if ((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3371 return Result.err(rcr);
3374 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO().read(trans, user,role);
3376 return Result.err(rr);
3378 for (UserRoleDAO.Data userRole : rr.value) {
3379 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3380 FutureDAO.Data fto = new FutureDAO.Data();
3381 fto.target=UserRoleDAO.TABLE;
3382 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3383 GregorianCalendar now = new GregorianCalendar();
3384 fto.start = now.getTime();
3385 fto.expires = org.expiration(now, Expiration.Future).getTime();
3387 fto.construct = userRole.bytify();
3388 } catch (IOException e) {
3389 trans.error().log(e, "Error while bytifying UserRole for Future");
3390 return Result.err(e);
3393 Result<String> rfc = func.createFuture(trans, fto,
3394 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3396 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3400 return Result.err(rfc);
3403 return func.extendUserRole(trans, userRole, false);
3406 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3411 path = "/authz/userRole/:user/:role",
3412 params = { "user|string|true",
3416 errorCodes = {403,404,406},
3417 text = { "Remove Role :role from User :user."
3421 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3422 Validator val = new ServiceValidator();
3423 if (val.nullOrBlank("User", usr)
3424 .nullOrBlank("Role", role).err()) {
3425 return Result.err(Status.ERR_BadData, val.errs());
3428 boolean mayNotChange;
3429 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3431 return Result.err(rrdd);
3434 RoleDAO.Data rdd = rrdd.value;
3435 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3437 // Make sure we don't delete the last owner of valid NS
3438 if (rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3439 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3442 if (mayNotChange=rns.notOK()) {
3443 if (!trans.requested(future)) {
3444 return Result.err(rns);
3448 Result<List<UserRoleDAO.Data>> rulr;
3449 if ((rulr=ques.userRoleDAO().read(trans, usr, role)).notOKorIsEmpty()) {
3450 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3451 + "Assigned to the Role [ " + role + " ]");
3454 UserRoleDAO.Data userRole = rulr.value.get(0);
3455 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3456 FutureDAO.Data fto = new FutureDAO.Data();
3457 fto.target=UserRoleDAO.TABLE;
3458 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3459 GregorianCalendar now = new GregorianCalendar();
3460 fto.start = now.getTime();
3461 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3463 Result<String> rfc = func.createFuture(trans, fto,
3464 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3466 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3470 return Result.err(rfc);
3473 return ques.userRoleDAO().delete(trans, rulr.value.get(0), false);
3479 path = "/authz/userRole/:user/:role",
3480 params = {"user|string|true",
3481 "role|string|true"},
3483 errorCodes = {403,404,406},
3484 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3488 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3489 final Validator v = new ServiceValidator();
3490 if (v.role(role).nullOrBlank("User", user).err()) {
3491 return Result.err(Status.ERR_BadData,v.errs());
3494 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3495 // if (ns.notOK()) return Result.err(ns);
3497 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3498 // May calling user see by virtue of the Role
3499 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3501 return Result.err(rrdd);
3503 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3505 return Result.err(rnd);
3508 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3509 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readUserInRole(trans, user, role);
3511 for (UserRoleDAO.Data data : rlurd.value) {
3516 @SuppressWarnings("unchecked")
3517 USERS users = (USERS) mapper.newInstance(API.USERS);
3518 mapper.users(trans, userSet, users);
3519 return Result.ok(users);
3524 path = "/authz/users/role/:role",
3525 params = {"user|string|true",
3526 "role|string|true"},
3528 errorCodes = {403,404,406},
3529 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3533 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3534 final Validator v = new ServiceValidator();
3535 if (v.nullOrBlank("Role",role).err()) {
3536 return Result.err(Status.ERR_BadData,v.errs());
3539 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3540 // if (ns.notOK()) return Result.err(ns);
3542 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3543 // May calling user see by virtue of the Role
3544 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3546 return Result.err(rrdd);
3549 boolean contactOnly = false;
3550 // Allow the request of any valid user to find the contact of the NS (Owner)
3551 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3553 if (Question.OWNER.equals(rrdd.value.name)) {
3556 return Result.err(rnd);
3560 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3561 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role);
3563 for (UserRoleDAO.Data data : rlurd.value) {
3564 if (contactOnly) { //scrub data
3565 // Can't change actual object, or will mess up the cache.
3566 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3568 scrub.rname = data.rname;
3569 scrub.role = data.role;
3570 scrub.user = data.user;
3578 @SuppressWarnings("unchecked")
3579 USERS users = (USERS) mapper.newInstance(API.USERS);
3580 mapper.users(trans, userSet, users);
3581 return Result.ok(users);
3585 * getUsersByPermission
3589 path = "/authz/users/perm/:type/:instance/:action",
3590 params = { "type|string|true",
3591 "instance|string|true",
3592 "action|string|true"
3595 errorCodes = {404,406},
3596 text = { "List all Users that have Permission specified by :type :instance :action",
3600 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3601 final Validator v = new ServiceValidator();
3602 if (v.nullOrBlank("Type",type)
3603 .nullOrBlank("Instance",instance)
3604 .nullOrBlank("Action",action)
3606 return Result.err(Status.ERR_BadData,v.errs());
3609 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3611 return Result.err(nss);
3614 Result<List<NsDAO.Data>> nsd = ques.nsDAO().read(trans, nss.value.ns);
3616 return Result.err(nsd);
3619 boolean allInstance = ASTERIX.equals(instance);
3620 boolean allAction = ASTERIX.equals(action);
3621 // Get list of roles per Permission,
3622 // Then loop through Roles to get Users
3623 // Note: Use Sets to avoid processing or responding with Duplicates
3624 Set<String> roleUsed = new HashSet<>();
3625 Set<UserRoleDAO.Data> userSet = new HashSet<>();
3627 if (!nss.isEmpty()) {
3628 Result<List<PermDAO.Data>> rlp = ques.permDAO().readByType(trans, nss.value.ns, nss.value.name);
3629 if (rlp.isOKhasData()) {
3630 for (PermDAO.Data pd : rlp.value) {
3631 if ((allInstance || pd.instance.equals(instance)) &&
3632 (allAction || pd.action.equals(action))) {
3633 if (ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3634 for (String role : pd.roles) {
3635 if (!roleUsed.contains(role)) { // avoid evaluating Role many times
3637 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByRole(trans, role.replace('|', '.'));
3638 if (rlurd.isOKhasData()) {
3639 for (UserRoleDAO.Data urd : rlurd.value) {
3650 @SuppressWarnings("unchecked")
3651 USERS users = (USERS) mapper.newInstance(API.USERS);
3652 mapper.users(trans, userSet, users);
3653 return Result.ok(users);
3656 /***********************************
3658 ***********************************/
3660 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3661 final Validator v = new ServiceValidator();
3662 if (v.nullOrBlank("User",user).err()) {
3663 return Result.err(Status.ERR_BadData,v.errs());
3666 Result<NsDAO.Data> rnd;
3667 // Users may look at their own data
3668 if (trans.user().equals(user)) {
3669 // Users may look at their own data
3671 int at = user.indexOf('@');
3672 if (at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3673 NsDAO.Data nsd = new NsDAO.Data();
3674 nsd.name = Question.domain2ns(user);
3675 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3677 return Result.err(rnd);
3680 rnd = ques.validNSOfDomain(trans, user);
3682 return Result.err(rnd);
3685 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3687 return Result.err(rnd);
3691 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readByUser(trans, user, yyyymm);
3693 return Result.err(resp);
3695 return mapper.history(trans, resp.value,sort);
3699 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3700 final Validator v = new ServiceValidator();
3701 if (v.nullOrBlank("Role",role).err()) {
3702 return Result.err(Status.ERR_BadData,v.errs());
3705 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3707 return Result.err(rrdd);
3710 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3712 return Result.err(rnd);
3714 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, role, "role", yyyymm);
3716 return Result.err(resp);
3718 return mapper.history(trans, resp.value,sort);
3722 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3723 final Validator v = new ServiceValidator();
3724 if (v.nullOrBlank("Type",type)
3726 return Result.err(Status.ERR_BadData,v.errs());
3729 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3730 Result<List<HistoryDAO.Data>> resp;
3731 if(type.startsWith(trans.user())) {
3732 resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3734 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3736 return Result.err(rnd);
3738 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3740 return Result.err(rnd);
3742 resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
3746 return Result.err(resp);
3748 return mapper.history(trans, resp.value,sort);
3752 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3753 final Validator v = new ServiceValidator();
3754 if (v.nullOrBlank("NS",ns).err()) {
3755 return Result.err(Status.ERR_BadData,v.errs());
3758 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3760 return Result.err(rnd);
3762 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3764 return Result.err(rnd);
3767 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, ns, "ns", yyyymm);
3769 return Result.err(resp);
3771 return mapper.history(trans, resp.value,sort);
3775 public Result<HISTORY> getHistoryBySubject(AuthzTrans trans, String subject, String target, int[] yyyymm, final int sort) {
3776 NsDAO.Data ndd = new NsDAO.Data();
3777 ndd.name = FQI.reverseDomain(subject);
3778 Result<Data> rnd = ques.mayUser(trans, trans.user(), ndd, Access.read);
3780 return Result.err(rnd);
3783 Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, subject, target, yyyymm);
3785 return Result.err(resp);
3787 return mapper.history(trans, resp.value,sort);
3790 /***********************************
3792 ***********************************/
3794 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3795 return createOrUpdateDelegate(trans, base, Question.Access.create);
3799 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3800 return createOrUpdateDelegate(trans, base, Question.Access.write);
3804 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3805 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3806 final ServiceValidator v = new ServiceValidator();
3807 if (v.delegate(trans.org(),rd).err()) {
3808 return Result.err(Status.ERR_BadData,v.errs());
3811 final DelegateDAO.Data dd = rd.value;
3813 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO().read(trans, dd);
3814 if (access==Access.create && ddr.isOKhasData()) {
3815 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3816 } else if (access!=Access.create && ddr.notOKorIsEmpty()) {
3817 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3819 Result<Void> rv = ques.mayUser(trans, dd, access);
3824 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3826 StringBuilder sb = new StringBuilder();
3827 sb.append(access.name());
3828 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3829 sb.append("Delegate ");
3830 sb.append(access==Access.create?"[":"to [");
3831 sb.append(rd.value.delegate);
3832 sb.append("] for [");
3833 sb.append(rd.value.user);
3835 return sb.toString();
3838 return Result.ok(); // Validate in code above
3843 Result<String> rfc = func.createFuture(trans, fd.value,
3844 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3846 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3849 return Result.err(rfc);
3851 case Status.ACC_Now:
3852 if (access==Access.create) {
3853 Result<DelegateDAO.Data> rdr = ques.delegateDAO().create(trans, dd);
3857 return Result.err(rdr);
3860 return ques.delegateDAO().update(trans, dd);
3863 return Result.err(fd);
3868 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3869 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3870 final Validator v = new ServiceValidator();
3871 if (v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3872 return Result.err(Status.ERR_BadData,v.errs());
3875 Result<List<DelegateDAO.Data>> ddl;
3876 if ((ddl=ques.delegateDAO().read(trans, rd.value)).notOKorIsEmpty()) {
3877 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3879 final DelegateDAO.Data dd = ddl.value.get(0);
3880 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3885 return ques.delegateDAO().delete(trans, dd, false);
3889 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3890 DelegateDAO.Data dd = new DelegateDAO.Data();
3891 final Validator v = new ServiceValidator();
3892 if (v.nullOrBlank("User", userName).err()) {
3893 return Result.err(Status.ERR_BadData,v.errs());
3896 Result<List<DelegateDAO.Data>> ddl;
3897 if ((ddl=ques.delegateDAO().read(trans, dd)).notOKorIsEmpty()) {
3898 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3900 dd = ddl.value.get(0);
3901 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3906 return ques.delegateDAO().delete(trans, dd, false);
3910 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
3911 final Validator v = new ServiceValidator();
3912 if (v.nullOrBlank("User", user).err()) {
3913 return Result.err(Status.ERR_BadData,v.errs());
3916 DelegateDAO.Data ddd = new DelegateDAO.Data();
3918 ddd.delegate = null;
3919 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3921 return Result.err(rv);
3924 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
3926 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().read(trans, user);
3928 if (dbDelgs.isOKhasData()) {
3929 return mapper.delegate(dbDelgs.value);
3931 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
3939 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
3940 final Validator v = new ServiceValidator();
3941 if (v.nullOrBlank("Delegate", delegate).err()) {
3942 return Result.err(Status.ERR_BadData,v.errs());
3945 DelegateDAO.Data ddd = new DelegateDAO.Data();
3946 ddd.user = delegate;
3947 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3949 return Result.err(rv);
3952 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
3954 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO().readByDelegate(trans, delegate);
3956 if (dbDelgs.isOKhasData()) {
3957 return mapper.delegate(dbDelgs.value);
3959 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
3966 /***********************************
3968 ***********************************/
3969 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
3971 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
3972 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
3974 return Result.err(rlad);
3976 int numApprs = rlad.value.size();
3978 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
3980 int numProcessed = 0;
3981 String user = trans.user();
3983 Result<List<ApprovalDAO.Data>> curr;
3984 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
3985 for (ApprovalDAO.Data updt : rlad.value) {
3986 if (updt.ticket!=null) {
3987 curr = ques.approvalDAO().readByTicket(trans, updt.ticket);
3988 if (curr.isOKhasData()) {
3989 final List<ApprovalDAO.Data> add = curr.value;
3990 // Store a Pre-Lookup
3991 apprByTicket = (trans1, noop) -> add;
3993 } else if (updt.id!=null) {
3994 curr = ques.approvalDAO().read(trans, updt);
3995 } else if (updt.approver!=null) {
3996 curr = ques.approvalDAO().readByApprover(trans, updt.approver);
3998 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
4001 if (curr.isOKhasData()) {
4002 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<>();
4003 Map<UUID, FutureDAO.Data> futureCache = new HashMap<>();
4004 FutureDAO.Data hasDeleted = new FutureDAO.Data();
4006 for (ApprovalDAO.Data cd : curr.value) {
4007 if ("pending".equals(cd.status)) {
4008 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
4010 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
4011 String delegator = cd.approver;
4012 if (updt.id!=null ||
4013 (updt.ticket!=null && user.equals(cd.approver)) ||
4014 (updt.ticket!=null && delegatedAction)) {
4015 if (updt.ticket.equals(cd.ticket)) {
4016 Changed ch = new Changed();
4017 cd.id = ch.changed(cd.id,updt.id);
4018 // cd.ticket = changed(cd.ticket,updt.ticket);
4019 cd.user = ch.changed(cd.user,updt.user);
4020 cd.approver = ch.changed(cd.approver,updt.approver);
4021 cd.type = ch.changed(cd.type,updt.type);
4022 cd.status = ch.changed(cd.status,updt.status);
4023 cd.memo = ch.changed(cd.memo,updt.memo);
4024 cd.operation = ch.changed(cd.operation,updt.operation);
4025 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
4026 // if (updt.status.equals("denied")) {
4027 // cd.last_notified = null;
4029 if (cd.ticket!=null) {
4030 FutureDAO.Data fdd = futureCache.get(cd.ticket);
4031 if (fdd==null) { // haven't processed ticket yet
4032 Result<FutureDAO.Data> rfdd = ques.futureDAO().readPrimKey(trans, cd.ticket);
4034 fdd = rfdd.value; // null is ok
4038 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
4040 if (fdd==hasDeleted) { // YES, by Object
4042 cd.status = "ticketDeleted";
4043 ch.hasChanged(true);
4045 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
4047 trans.info().printf("Approval Status %s is not actionable",cd.status);
4048 } else if (apprByTicket!=null) {
4049 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
4053 if (delegatedAction) {
4054 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
4056 futureCache.put(cd.ticket, hasDeleted);
4060 ch.hasChanged(true);
4061 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
4062 futureCache.put(cd.ticket, hasDeleted);
4067 trans.info().log(rv.toString());
4074 if (ch.hasChanged()) {
4075 ques.approvalDAO().update(trans, cd, true);
4084 if (numApprs==numProcessed) {
4087 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
4091 private static class Changed {
4092 private boolean hasChanged = false;
4094 public<T> T changed(T src, T proposed) {
4095 if (proposed==null || (src!=null && src.equals(proposed))) {
4102 public void hasChanged(boolean b) {
4106 public boolean hasChanged() {
4112 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
4113 final Validator v = new ServiceValidator();
4114 if (v.nullOrBlank("User", user).err()) {
4115 return Result.err(Status.ERR_BadData,v.errs());
4118 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByUser(trans, user);
4120 return mapper.approvals(rapd.value);
4122 return Result.err(rapd);
4127 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
4128 final Validator v = new ServiceValidator();
4129 if (v.nullOrBlank("Ticket", ticket).err()) {
4130 return Result.err(Status.ERR_BadData,v.errs());
4134 uuid = UUID.fromString(ticket);
4135 } catch (IllegalArgumentException e) {
4136 return Result.err(Status.ERR_BadData,e.getMessage());
4139 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByTicket(trans, uuid);
4141 return mapper.approvals(rapd.value);
4143 return Result.err(rapd);
4148 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
4149 final Validator v = new ServiceValidator();
4150 if (v.nullOrBlank("Approver", approver).err()) {
4151 return Result.err(Status.ERR_BadData,v.errs());
4154 List<ApprovalDAO.Data> listRapds = new ArrayList<>();
4156 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO().readByApprover(trans, approver);
4157 if (myRapd.notOK()) {
4158 return Result.err(myRapd);
4161 listRapds.addAll(myRapd.value);
4163 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO().readByDelegate(trans, approver);
4164 if (delegatedFor.isOK()) {
4165 for (DelegateDAO.Data dd : delegatedFor.value) {
4166 if (dd.expires.after(new Date())) {
4167 String delegator = dd.user;
4168 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO().readByApprover(trans, delegator);
4170 for (ApprovalDAO.Data d : rapd.value) {
4171 if (!d.user.equals(trans.user())) {
4180 return mapper.approvals(listRapds);
4184 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4187 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4188 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4189 return ques.clearCache(trans,cname);
4191 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4192 trans.user(),ROOT_NS,CACHE,cname);
4196 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4199 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4200 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4201 Result<Void> v=null;
4202 for (int i: segment) {
4203 v=ques.cacheClear(trans,cname,i);
4209 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4210 trans.user(),ROOT_NS,CACHE,cname);
4214 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4217 public void dbReset(AuthzTrans trans) {
4218 ques.historyDAO().reportPerhapsReset(trans, null);